Одна из особенностей классов менеджеров компоновки заключается в том, что они не являются виджетами. Взамен этого они наследуют свойства класса QLayout, который, в свою очередь, является наследником класса QObject. На данном рисунке виджеты выделены сплошными линиями, а менеджеры компоновки очерчены пунктирными линиями, чтобы подчеркнуть их различие. При работе приложения менеджеры компоновки невидимы.
При добавлении внутренних менеджеров компоновки к родительскому менеджеру компоновки (строки 25, 33 и 34) для них автоматически устанавливается родительская связь. Затем, когда главный менеджер компоновки устанавливается для диалога (строка 35), он становится дочерним элементом диалога и все виджеты в менеджерах компоновки становятся дочерними элементами диалога. Иерархия полученных родословных связей представлена на рис. 2.3.
Рис. 2.3. Родословная объектов диалогового окна поиска данных.
36 setWindowTitle(tr("Find"));
37 setFixedHeight(sizeHint().height());
38 }
Наконец, мы задаем название диалогового окна и устанавливаем фиксированной его высоту, поскольку в диалоговом окне нет виджетов, которым может понадобиться дополнительное пространство по вертикали. Функция QWidget::sizeHint() возвращает «идеальный» размер виджета.
На этом завершается рассмотрение конструктора FindDialog. Поскольку нами использован оператор new при создании виджетов и менеджеров компоновки, нам,
последовательность таких переходов соответствует порядку создания виджетов. Эту последовательность можно изменить с помощью функции QWidget::setTabOrder() .
Обеспечение осмысленного порядка переходов с одного виджета на другой с помощью клавиши табуляции и применение клавиш быстрого доступа позволяют использовать все возможности приложений тем пользователям, которые не хотят (или не могут) пользоваться мышкой. Тот, кто быстро работает с клавиатурой, также предпочитает иметь возможность полного управления приложением посредством клавиатуры.
В диалоговое окно поиска будет использовано нами в реальном приложении и мы подключим сигналы findPrevious() и findNext() к некоторым слотам.
Подробное описание технологии сигналов и слотов
Слоты почти совпадают с обычными функциями, которые объявляются внутри классов С++ (функциичлены). Они могут быть виртуальными, они могут быть перегруженными, они могут быть открытыми (public), защищенными (protected) и закрытыми (private), они могут вызываться непосредственно, как и любые другие функциичлены С++, и их параметры могут быть любого типа. Однако слоты (в отличие от обычных функцийчленов) могут подключаться к сигналам, и в результате они будут вызываться при каждом генерировании соответствующего сигнала.
Оператор connect() выглядит следующим образом:
connect (отправитель, SIGNAL(сигнал ), получатель, SLOT(слот ));
где отправитель и получатель являются указателями на объекты QObject и где сигнал и слот являются сигнатурами функций без имен параметров. Макросы 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 &)));
Имеется одно исключение, а именно: если у сигнала больше параметров, чем у подключенного слота, то дополнительные параметры просто игнорируются:
connect(ftp, SIGNAL(rawCommandReply(int, const QString &),
this, SLOT(checkErrorCode(int)));
Если параметры имеют несовместимые типы либо будет отсутствовать сигнал или
слот, то Qt выдаст предупреждение во время выполнения программы, если сборка программы проводилась в отладочном режиме. Аналогично Qt выдаст предупреждение, если в сигнатуре сигнала или слота будут указаны имена параметров.