The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Программирование, языки" / Оглавление документа

2.2. Сигналы и слоты.

Сигналы и слоты являются одним из фундаментальных механизмов в Qt. Он позволяет наладить обмен информацией между объектами, которые ничего не знают друг о друге. Мы уже пробовали присоединять сигналы к слотам, объявляли свои собственные сигналы и слоты, выполняли реализацию своих слотов и посылали свои сигналы. Теперь рассмотрим этот механизм поближе.

По своей природе, слоты очень близки к обычным функциям-членам в языке C++. Они могут быть виртуальными, они могут подвергаться перегрузке, они могут быть публичными, защищенными или приватными и они могут вызываться напрямую, как и обычные функции-члены. Отличие состоит в том, что слот может быть подключен к сигналу. В этом случае, функция-слот вызывается автоматически всякий раз, когда посылается сигнал.

Объявление connect() выглядит следующим образом:

connect(sender, SIGNAL(signal), receiver, SLOT(slot));      
      
где sender и receiver -- это указатели на экземпляры класса QObject (или его потомки), а signal и slot -- это сигнатуры функций. Макросы SIGNAL() и SLOT() по сути преобразуют свои аргументы в строки. В наших примерах мы до сих пор подключали к каждому из сигналов только один слот. Однако это не единственный способ. Соединяемые сигналы и слоты должны иметь идентичные сигнатуры (т.е. количество и типы входных аргументов):
connect(ftp, SIGNAL(rawCommandReply(int, const QString &)), 
        this, SLOT(processReply(int, const QString &)));      
      
Исключение составляет случай, когда сигнал имеет большее число аргументов, чем слот. В этом случае "лишние" аргументы просто не передаются в слот.

Если типы входных аргументов не совместимы, или сигнал или слот не определены, Qt выдаст предупреждение во время исполнения. Точно так же Qt выдаст предупреждение, если в сигнатуры сигналов или слотов включены имена аргументов (в методе connect()).

            
Метаобъектная Система в библиотеке Qt
            

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

Этот механизм получил название Meta Object System и предоставляет два ключевых сервиса: сигналы-слоты и интроспекцию. Интроспекция позволяет получать метаинформацию о потомках класса QObject во время исполнения, включая список поддерживаемых сигналов, слотов и имя класса объекта. Этот механизм также реализует поддержку свойств объектов (используются в Qt Designer) и перевод текста (для нужд интернационализации).

Стандарт C++ не обеспечивает возможность получения динамической метаинформации, которая необходима метаобъектной системе Qt. Поэтому данная проблема была решена созданием дополнительного инструмента moc (метаобъектный компилятор). Он собирает всю необходимую информацию из классов Q_OBJECT и делает ее доступной через вызовы обычных функций языка C++, что позволяет метаобъектной системе работать с любым компилятором C++.

Механизм работает следующим образом:

  • Макрос Q_OBJECT объявляет ряд функций, который должны присутствовать в каждом потомке QObject: metaObject(), className(), tr() и ряд других.

  • Утилита moc генерирует реализацию сигналов и функций, объявленных макросом Q_OBJECT.

  • Эти функции используются методами connect() и disconnect().



Все действия выполняются автоматически, утилитами qmake и moc, так что вы довольно редко будете вспоминать об этом. Но если вас одолевает любопытство -- загляните в исходные файлы, созданные moc, и посмотрите -- что да как.

До сих пор мы использовали сигналы и слоты исключительно с виджетами. Однако, этот механизм реализован непосредственно в классе QObject и область его применения не ограничивается графическим интерфейсом. Он может использоваться любым классом, наследником QObject:

class Employee : public QObject
{
    Q_OBJECT
public:
    Employee() { mySalary = 0; }
    int salary() const { return mySalary; }
public slots:
    void setSalary(int newSalary);
signals:
    void salaryChanged(int newSalary);
private:
    int mySalary;
};
void Employee::setSalary(int newSalary)
{
    if (newSalary != mySalary) {
         mySalary = newSalary;
         emit salaryChanged(mySalary);
    }
}
      


Обратите внимание на реализацию слота setSalary(). Сигнал salaryChanged() посылается только в том случае, когда newSalary != mySalary. Такой способ предотвращает попадание в бесконечный цикл при наличии обратной связи с другим объектом.




Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2021 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру