Вводная часть:
Qt – это не только элементы графического интерфейса. Этот фреймворк представляет собой взаимосвязанную систему. Родственность Qt-объектов осуществляется через наследование класса QObject
. А связи между ними через сигнально-слотовую систему.В этой статье будут описаны основные классы и полезные особенности этой библиотеки.
QObject
Это базовый класс для всех объектов Qt. Его наследует любой класс использующий сигналы и слоты. Он обеспечивает возможность соединения объектов друг с другом. А также предоставляет к этому полезную функциональность. Во введение этого базового класса находиться:
- Прослеживание за потомками и родителями и возвращение указателей на них (Наследственная информация).
- Программная реализация таймера
- Динамические свойства
- Интернационализация приложения
QApplication
Это сердце любого приложения использующего графические элементы.Объект этого класса должен быть создан в единственном экземпляре перед основным кодом программы. В его сферу ответственности входит:
- Инициализирует приложение в соответствии с пользовательскими настройками.
- Выполняет обработку сообщений и передачу их соответствующим виджетам.
- Анализирует аргументы командной строки и соответствующим образом устанавливает свой внутреннее состояние.
- Определяет внешний вид приложения через установку стиля и изменение разрешенных цветов.
- Предоставляет ссылки на глобальный буфер обмена(
clipboard()
) и другие полезные объекты. - Следит за открытыми окнами приложения и может выдать информацию о них.
- Управляет видом иконки курсора.
- И другие полезные функции.
Слоты и сигналы:
Для того чтобы объекты могли общаться, был введён механизм сигналов и слотов. С помощью этого объекты сообщают друг другу о произошедших событиях и отсылают нужные данные. Слот, как и функция-член, может быть публичной, приватной, защищённой или виртуальной. Он вызывается, если приходит подсоединённый к нему сигнал. Он в свою очередь генерируется, если в коде обработки события имеется вызов(макрос) emit signal().
Для себя можно представить определенную схему:
Событие ➞Генерация сигнала➞Передача параметров в слот.
Как выглядит в программе:
«Щелчок по кнопке» ➞ программная обработка ➞ signal(clicked()) ➞ slot(myslot()).
Основа для создания:
В классе, который должен будет иметь свои сигналы и слоты, нужно произвести наследование от QObject
или другого класса библиотеки, наследующего его, и определить макрос Q_Object
, с помощью этого объявления компилятор понимает, что необходимо сгенерировать из написанного qt-кода, который использует свои нововведения, в равнозначный шаблонный код стандартного C++. Начиная с Qt 5.0 появился новый способ соединения:
1)Ранняя версия:
QObject::connect(&Отправитель,SIGNAL(mysignal()),&Адресат,SLOT(myslot()));
В шаблонной версии выглядит так:
bool QObject::connect (const QObject * sender, const char * signal, const QObject * receiver, const char * method, type Qt::ConnectionType = Qt::AutoConnection)
Для создания связи необходимо прописать:
- Отправителя и его сигнал.
- Получателя и его слот.
- А также тип соединения, который зависит от того используете вы соединение в потоке или нет. По умолчанию тип соединения определяется автоматически.
Этот старый способ соединения использует механизм обработки строк. Если не существует сигнала или слота с данными именами, то соединения не происходит, а в консоль не отсылается сообщение об ошибке. Разъединение происходит при уничтожении объекта автоматически. В редких случаях используется такая форма для отключения сигналов:
QObject::disconnect(&Отправитель,SIGNAL(mysignal()),&Адресат,SLOT(myslot()));
2)connect(&Отправитель,&Class_1::mysignal,&Адресат,&Class_2::myslot);
Достоинства:
- Проверка существования сигналов и слота, типов, или если
Q_OBJECT
отсутствует(выдаёт ошибки). - Параметр может быть определением типа или с различными спецификаторами пространства имен.
- Возможность автоматического приведения типов, если есть неявное преобразование (например, от QString до QVariant)
- Возможно соединиться с любой функцией-членом класса(произведённого от QObject),а не только со слотами.
Недостатки:
- Более сложный синтаксис(Вы должны определить тип своего объекта)
- Очень сложный синтаксис в случаях перегрузок
- Параметры по умолчанию в слоте теперь не поддерживаются.
Нововведение: возможность соединения с простой функцией.
Благодаря новому синтаксису, появилась возможность соединения с функциями не являющимися слотами. Пример:connect(sender, &Sender::valueChanged, saveFunction);
Такая форма используется для разъединения:
Оба способа соединения разрешены для применения в программе. Так-как у них имеются различия нужно выбирать тот способ, который лучше подходит под ваши нужды.
Разберём на примере использование слотов и сигналов в программе.
Пример:
Добавьте в созданный на предыдущем уроке "sppstudio"
новый подпроект lesson_2(Qt Widget).
Очистите его от посторонних файлов, оставив в нём main.cpp.Создайте в нем файлы myclass.h и myclass.cpp. Давайте придумаем функциональность для нашей программы. Пусть она при нажатии на кнопку создаёт окна и если число созданных окон превысит 5, то она закончит выполнение.
Перед вами реализация её класса:
//myclass.h #ifndef MYCLASS #define MYCLASS #include <QLabel> #include <QPushButton> #include <QDialog> #include <QHBoxLayout> #include <QDebug> //отображение числа нажатий class MyClass:public QObject { Q_OBJECT private: QPushButton * butt; QHBoxLayout * hbox; QWidget *window; static int counter;//счетчик объектов public: MyClass(); ~MyClass() { qDebug()<<"delete object MyClass"; delete butt; delete hbox; delete window; } private slots: void incCounter();//добавляет единицу к counter при вызове void newWindow();//создаёт новое окно signals: s_transmitter();//сигнал передатчик }; #endif // MYCLASS
В заголовочном файле прописываем слоты, сигнал и члены класса.
Обратите внимания на макросы:
Q_Object — нужно прописывать в любом классе использующего свои слоты и сигналы.
private slots: и signals: — здесь собственно они прописываются.
Определения методов у нас находятся в файле .cpp
Перейдём к его детальному рассмотрению:
//myclass.cpp #include "myclass.h" #include <QString> #include <QApplication> MyClass::MyClass() { butt = new QPushButton(" Создать ещё окно "); QString str; str = "Экземпляр №"+QString::number(counter); hbox = new QHBoxLayout; hbox->addWidget(butt); connect(butt,SIGNAL(clicked()),this,SLOT(incCounter())); connect(this,SIGNAL(s_transmitter()),this,SLOT(newWindow())); /* *Это старая версия соединения сигнала и слота *А ниже распологается новая: *connect(butt,&QPushButton::clicked,this,&MyClass::incCounter); *Вы можете выбрать эту версию *Для этой маленькой программы не будет большой разницы какой тип вы используете */ window = new QWidget; window->setWindowTitle(str); window->setLayout(hbox); window->resize(230,45); window->move(200,80*counter); window->show(); } void MyClass::incCounter() { ++counter; if(counter>5) { QCoreApplication::quit(); return; } emit s_transmitter(); } void MyClass::newWindow() { MyClass * m = new MyClass(); m->setParent(this); } int MyClass::counter = 1;
Со строки 6 начинается описание конструктора MyClass
. В нём создаётся окно с кнопкой и соединяются слоты с сигналами. В 16-17 происходит соединение старого типа. За настройки вида приложения отвечают строки 27-31.
27: Установка названия окна
29: Размеры окна по x и y
30: Перемещает каждое новое окно вниз чтобы не нагромождать их на одном месте.
Последняя строка отвечает за появление окна на дисплее.
Функция incCounter
отвечает за инкриминирование счётчика, вызов сигнала(строка 41) и выход из программы(36-40).
Функция newWindow
создаёт новое окно и устанавливает ему родителя.Им становится объект у которого была нажата кнопка.
//main.cpp #include <QApplication> #include "myclass.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); MyClass myclass; a.exec(); return 0; }
И наконец main.cpp
.
В нём прописывается автоматическая переменная-объект, которая удаляется при завершении программы.
Резюме:
Собственно в следующих статьях будет произведён упор не на описании базовых функций, а об использовании полезных особенностей библиотеки на практике. Здесь вы можете найти русский перевод документации по Qt 4.3 – 4.8. Описываются классы библиотеки, основные свойства и инструменты разработки.