Шаг 11.
Библиотека Qt.
Определение сигнала

    На этом шаге рассмотрим определение сигнала.

    Сигналы (signals) окружают нас в повседневной жизни везде: звонок будильника, жест регулировщика, а также и в не повседневной, например индейский сигнальный костер и т. д. В программировании с использованием Qt под этим понятием подразумеваются методы, которые в состоянии осуществлять пересылку сообщений.

    Причиной для появления сигнала может быть сообщение об изменении состояния управляющего элемента, например перемещение ползунка. На подобные изменения присоединенный объект, отслеживающий эти сигналы, может соответственно отреагировать, хотя это и не обязательно. Этот очень важный момент говорит о том, что соединяемые объекты могут быть абсолютно независимы и реализованы отдельно друг от друга.

    Это позволяет объекту, отправляющему сигналы, не беспокоиться о том, что впоследствии будет происходить с этими сигналами. Объект, отправляющий сигналы, может даже и не догадываться, что их принимают и обрабатывают другие объекты. Благодаря такому разделению, можно разбить большой проект на компоненты, которые будут разрабатываться разными программистами в отдельности, а потом соединяться при помощи сигналов и слотов вместе.

    Это делает код очень гибким и легко расширяемым; если один из компонентов устареет или должен будет реализован иначе, то все другие компоненты, участвующие в коммуникации с этим компонентом, и сам проект в целом, не изменятся. Новый компонент после разработки встанет на место старого и будет подключен к основной программе при помощи тех же самых сигналов и слотов.

    Это делает библиотеку Qt особенно привлекательной для реализации компонентно-ориентированных приложений. Однако, большое количество взаимосвязей приводит к возникновению сильно связанных систем, в которых даже незначительные изменения могут привести к непредсказуемым последствиям.

    Сигналы определяются в классе, как и обычные методы, только без реализации. С точки зрения программиста они являются только прототипами методов, содержащихся в заголовочном файле определения класса.

    Всю дальнейшую заботу о реализации кода для этих методов берет на себя MOC. Методы сигналов не должны возвращать каких-либо значений, и поэтому перед именем метода всегда должно стоять void.

    Сигнал не обязательно соединять со слотом. Если соединения не произошло, то он просто не будет обрабатываться. Подобное разделение отправляющих и получающих объектов исключает возможность того, что один из подсоединенных слотов каким-то образом сможет помешать объекту, отправившему сигналы.

    Библиотека предоставляет большое количество уже готовых сигналов для существующих элементов управления. В основном, для решения поставленных задач хватает этих сигналов, но иногда возникает необходимость реализации новых сигналов в своих классах.

    Пример определения сигнала

class MySignal {
      Q_OBJECT
      ...
      signals:
              void doIt();
      ...
};   

    Обратите внимание на метод сигнала doIt(). Он не имеет реализации, эту работу принимает на себя MOC, обеспечивая примерно такую реализацию:

void MySignal::doIt()
{
   QMetaObject::activate(this, &staticMetaObject, 0, 0);
}                                                

    Из сказанного становится ясно, что не имеет смысла определять сигналы как private, protected или public, т. к. они играют роль вызывающих методов.

    Выслать сигнал можно при помощи ключевого слова emit. Ввиду того, что сигналы играют роль вызывающих методов, конструкция отправки сигнала emit doIt() приведет к обычному вызову метода doIt().

    Сигналы могут отправляться из классов, которые их содержат. Например, сигнал doIt() может отсылаться только объектами класса MySignal, и никакими другими.

    Чтобы иметь возможность отослать сигнал программно из объекта этого класса, следует добавить метод sendSignal(), вызов которого заставит объект класса MySignal отправлять сигнал doIt(), как это показано в примере ниже.

class MySignal {
      Q_OBJECT
      public:
      void sendSignal()
      {
           emit doIt();
      }
      signals:
           void doIt();
};

    Сигналы также имеют возможность высылать информацию, передаваемую в параметре. Например, если возникла необходимость передать в сигнале строку текста, то можно реализовать это следующим образом:

class MySignal : public QObject {
      Q_OBJECT
      public:
      void sendSignal()
      {
           emit sendString("Information");
      }
      signals:
           void sendString(const QString&);
};

    На следующем шаге рассмотрим определение слота.




Предыдущий шаг Содержание Следующий шаг