Символы кириллицы выводит некорректно. Как сделать чтобы выводился читабельный текст на русском языке? Тип приложения - не Qt, Qt Creator 4.5.0 основан на Qt 5.10.0. Win7.
|
Создание графического интерфейса средствами Qt
13.4 Сигнально-слотовые соединения
Одной из фундаментальных возможностей в Qt является взаимодействие объектов с помощью сигнально-слотовых соединений. Для осознания преимуществ, которые предоставляет такая возможность, рассмотрим как устроено взаимодействие между объектами в программе.
Любая объектно-ориентированная программа состоит из объектов, которые взаимодействуют между собой. Каждый из объектов обладает состоянием, которое определяет совокупность данных, которые хранит объект в данный момент. В ответ на взаимодействие с объектом его состояние может измениться. Например, объект, реализующий сетевое соединение, может получить новые отправленные данные, а объект, реализующий кнопку на окне пользовательского интерфейса, может быть нажат пользователем. Таким образом объект изменил своё состояние — и он может уведомить об этом другой объект посылая ему сообщение об изменении. Практически это взаимодействие обычно реализуют с помощью вызова метода объекта, которому нужно отправить сообщение. Этот метод должен выполнять соответствующие действия в ответ на изменение. Каждый объект выполняет свою роль, а взаимодействие между ними происходит за счёт взаимного вызова методов (прямого или косвенного), каждый из которых должен выполнять собственную чёткую функцию. Таким разделением получают уменьшение сложности кода — за счёт чёткого распределения ответственности между объектами — а, следовательно, получают и гибкость, способность классов к повторному использованию, простоту сопровождения кода. Очень важно хорошее понимание этих ключевых идей — разделение ответственности между объектами в программе и организации взаимодействия между ними на основе чётко определённых интерфейсов (наборов методов), вытекающих из фундаментальных понятий ООП: абстракции и инкапсуляции.
Таким образом, для реализации такого взаимодействия программисту нужно вызвать метод другого объекта в ответ на изменение состояния. Объект, который сменил состояние, может для этого просто хранить указатель на другой объект, чей метод нужно вызвать. В ответ на изменение состояния он будет обращаться через указатель и вызывать метод. Однако, в таком случае теряется гибкость. Например, в случае с элементами управления в окне программы, придётся программировать каждый элемент отдельно — наследовать от класса элемента управления, добавлять указатель и переопределять метод для обработки действий пользователя с целью взаимодействия с другими объектами в программе. К тому же такая связь не может быть динамической и задаётся жёстко на этапе компиляции.
Конечно можно передавать указатель на метод, который будет вызываться в ответ (callback), но такой подход тоже имеет некоторые недостатки (меньшая безопасность, всегда работает как прямой вызов метода, нужны знания о деталях реализации). Именно поэтому в Qt используется концепция сигнально-слотовых соединений.
Сигнально-слотовые соединения являются простым, но в то же время важным средством кроссплатформенного инструментария разработки Qt. Один объект при изменении своего состояния может сообщить других с помощью сигнала. Визуальные компоненты тоже вырабатывают сигналы в ответ на действия пользователя (например, нажатия кнопки, установки флага, изменения положения слайдера, редактирования текста в поле ввода и т. п.). Другие объекты могут присоединиться к сигналу слотом — специальным методом, который реализует некоторую функциональность и вызывается каждый раз, когда был выпущен присоединённый к нему сигнал. Как отмечалось ранее, сигнально-слотовые соединения могут использоваться как для взаимодействия объектов в пределах одного потока, так и между потоками (при соответствующих условиях), также возможна организация отложенного выполнения операций.
Для задания соединения используют метод connect() класса QObject. Метод принимает пять параметров:
- указатель на объект, который посылает сигнал (sender);
- название сигнала (signal) и его параметры, которые задаются с помощью макроса SIGNAL();
- указатель на объект, который получает сигнал (receiver);
- название слота (slot) и его параметры, которые задаются с помощью макроса SLOT(), или название другого сигнала, будет эмитироваться (выпускаться) в ответ;
- тип сигнально-слотового соединения (имеет значение по умолчанию Qt::AutoConnection).
В следующем примере мы продемонстрируем сигнально-слотовое соединения между кнопкой QPushButton и виджетом-окном QWidget. В ответ на нажатие кнопки (сигнал clicked()), вызывается метод-слот close(), который закрывает окно. Заметим, что слоты имеют спецификатор доступа (private/protected/public) и вызывают их как и обычные методы класса. Этим они не отличаются от других методов.
connect(lPushButton,SIGNAL(clicked()),lWindow, SLOT(close()));
Сигнально-слотовые соединения могут отличаться методом вызова слота, либо механизмом соединения. Тип соединения можно указать при его создании:
- Qt::AutoConnection — тип соединения по умолчанию. При соединении объектов в пределах потока ведёт себя как Direct Connection, иначе — как Queued Connection;
- Qt::DirectConnection — слот вызывается немедленно после того, как был выпущен сигнал. По сути это напоминает обычний вызов слота как метода;
- Qt::QueuedConnection — слот выполняется, как только управления перейдёт к очереди обработки сообщений потока получателя;
- Qt::BlockingQueuedConnection — то же, что и Queued Connection, но поток, из которого был выпущен сигнал блокируется, пока выполнение слота не будет завершено. Этот тип соединения должен использоваться только когда взаимодействующие объекты находятся в разных потоках.
- Qt::UniqueConnection — этот тип соединения такой же как и Qt::AutoConnection, но соединение происходит только тогда, когда оно уникально (то есть такое, которое не дублирует уже существующие соединений).
Также с помощью соединений между слотами и сигналами может происходить передача параметров. Например, визуальный элемент QCheckBox выпускает сигнал toggled() каждый раз при установке и снятии флажка. Сигнал toggled() передаёт один параметр — булевое значение: true — если флажок установлен, false — если нет. Мы сможем соединить его со слотом setChecked() кнопки, который также принимает булево значение и устанавливает кнопку в положение "включено" (true) или "выключено" (false). Заметьте: мы использовали метод setCheckable(), который устанавливает для кнопки режим переключения между двумя состояниями.
lPushButton->setCheckable ( true ); connect ( lCheckBox, SIGNAL( toggled ( bool ) ), lPushButton,SLOT( setChecked ( bool ) ) );
- порядок и тип параметров должен совпадать у объекта, который передаёт сигнал, и у объекта-получателя;
- сигнал или слот получателя может опускать некоторые или все остальные параметры, при этом порядок и тип параметров, которые остались у получателя, должны совпадать с первыми параметрами сигнала.
Один и тот же сигнал объекта может быть подключён к нескольким различным сигналам и слотам другого объекта и наоборот. При этом последовательность, в которой будут вызываться присоединённые сигналы и слоты будет соответствовать порядку в котором их соединили. Также надо помнить, что одно и то же соединение может быть выполнено несколько раз подряд. В таком случае при вызове сигнала слот сработает столько же раз, сколько раз было повторно выполнено соединение. Для того, чтобы избежать этого, необходимо передавать тип соединения Qt::UniqueConnection каждый раз в случаях, когда создание повторных соединений не требуется.
Возможность создания перекрёстного сигнально-слотового соединения продемонстрирована в следующем примере:
connect ( lCheckBox, SIGNAL( toggled ( bool ) ), lPushButton,SLOT( setChecked ( bool ) ) ); connect ( lPushButton, SIGNAL( toggled ( bool ) ), lCheckBox,SLOT( setChecked ( bool ) ) );
Здесь мы видим взаимодействие между обоими элементами управления. При установке\сбросе флажка кнопка будет устанавливаться во включённое состояние или сбрасываться и наоборот.