Сигналы и слоты являются одним из фундаментальных механизмов в Qt. Он позволяет наладить обмен информацией между объектами, которые ничего не знают друг о друге. Мы уже пробовали присоединять сигналы к слотам, объявляли свои собственные сигналы и слоты, выполняли реализацию своих слотов и посылали свои сигналы. Теперь рассмотрим этот механизм поближе.
По своей природе, слоты очень близки к обычным функциям-членам в языке C++. Они могут быть виртуальными, они могут подвергаться перегрузке, они могут быть публичными, защищенными или приватными и они могут вызываться напрямую, как и обычные функции-члены. Отличие состоит в том, что слот может быть подключен к сигналу. В этом случае, функция-слот вызывается автоматически всякий раз, когда посылается сигнал.
Объявление connect() выглядит следующим образом:
connect(sender, SIGNAL(signal), receiver, SLOT(slot));
где sender и receiver -- это указатели на экземпляры
класса QObject (или его потомки), а
signal и
slot -- это сигнатуры функций. Макросы SIGNAL() и SLOT() по сути преобразуют свои аргументы
в строки. В наших примерах мы до сих пор подключали к каждому из
сигналов только один слот. Однако это не единственный способ.
Один сигнал может быть подключен к нескольким слотам:
connect(slider, SIGNAL(valueChanged(int)),
spinBox, SLOT(setValue(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SLOT(updateStatusBarIndicator(int)));
Когда подается сигнал, то функции-слоты вызываются одна за
другой, в порядке подключения.К одному слоту может быть подключено несколько сигналов:
connect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));
connect(calculator, SIGNAL(divisionByZero()),
this, SLOT(handleMathError()));
Когда посылается какой-либо из сигналов -- вызывается
функция-слот.Сигнал может быть подключен к другому сигналу:
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SIGNAL(updateRecord(const QString &)));
Когда посылается первый сигнал, то вслед за ним подается и
второй. С точки зрения программы, соединение типа сигнал-сигнал ничем
не отличается от соединения типа сигнал-слот.Связь между сигналом и слотом может быть разорвана:
disconnect(lcd, SIGNAL(overflow()),
this, SLOT(handleMathError()));
Необходимость в этом возникает довольно редко, поскольку Qt сама
автоматически разрывает соединение, если один из объектов
уничтожается.
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++. Механизм работает следующим образом:
Все действия выполняются автоматически, утилитами 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. Такой способ предотвращает попадание в бесконечный цикл при наличии обратной связи с другим объектом.
Пред. | В начало | След. |
Создание диалогов. | На уровень выше | Быстрая разработка диалогов. |