Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

Разработка приложений с использованием Qt, часть 3

Оригинал: Developing Apps on Qt, Part 3
Автор: Manoj Kumar
Дата публикации: 27 марта 2012 г.
Перевод: А.Панин
Дата публикации перевода: 7 октября 2012 г.

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

Механизм сигналов и слотов позволяет объектам взаимодействовать друг с другом. В повседневной жизни мы можем найти множество примеров подобного механизма; например, светофор - когда загорается красный свет, вы останавливаете свое транспортное средство. Красный свет является сигналом, а остановка транспортного средства - слотом. Когда светофор генерирует сигнал включения красного света, вы вызываете слот, т.е. вы останавливаете транспортное средство.

Для правильного понимания этого механизма нам необходимо попрактиковаться в работе с Qt - разработать нашу первую программу с графическим интерфейсом, использующую сигналы и слоты. Откройте Qt Creator. Перейдите в меню Файл -> Новый файл или проект -> Проект Qt Widget -> GUI приложение Qt (File -> New File or Project -> Qt Widget Project -> Qt GUI Application) (Рисунок 1). Выберите директорию для размещения и название вашего проекта (Рисунок 2). В качестве цели выберите Desktop (Рисунок 3). (картинки кликабельны)

Qt Creator Выбор директории размещения Выбор цели проекта
Рис.1: Qt Creator   Рис.2: Выбор директории размещения   Рис.3: Выбор цели проекта

После этого нужно будет ответить на вопросы о классах. В поле выбора базового класса вы можете обнаружить три варианта, используемые для разных целей. Мы рассмотрим их в следующей статье. На данный момент следует выбрать QDialog в качестве базового класса (Рисунок 4). Дайте имя вашему классу, после чего нажмите "Далее", и, наконец, нажмите "Завершить".

Создание класса
Рисунок 4: Создание класса

Сразу после этого Qt Creator откроет ваш новый проект (Рисунок 5) в окне проекта слева. В составе проекта должен присутствовать один файл проекта с названием project-name.pro, а в моем случае 1.pro, так как я назвал мой проект "1".

Редактор кода
Рисунок 5: Редактор кода

Ниже расположены три директории: Заголовочные (Headers), Исходники (Sources) и Формы (Forms), в в которых находятся файлы соответствующих типов. Откройте любой файл при помощи двойного клика. Класс, которому мы дали название в процессе создания проекта, состоит из трех файлов: dialog.h (заголовочный файл), dialog.cpp (исходный код C++) и dialog.ui (файл пользовательского интерфейса или формы). Откройте файл пользовательского интерфейса в редакторе с помощью двойного клика (Рисунок 6).

Редактор пользовательского интерфейса
Рисунок 6: Редактор пользовательского интерфейса

Панель слева содержит список элементов графического интерфейса, которые могут быть помещены в окне диалога при помощи простого перетаскивания. Давайте используем нашем первом примере строку (Label) и две кнопки (Push Button). Окно диалога должно выглядеть так, как показано на рисунке 7.

Окно диалога
Рисунок 7: Окно диалога

Для простоты не будем использовать элементы размещения (Layouts). При помощи двойных кликов измените текст кнопок на "Count" и "Quit"; используйте двойной клик по отношению к строке и удалите текст. Нажатие на кнопку "Count" должно увеличивать значение счетчика и выводить его в качестве текста строки, а нажатие на кнопку "Quit" - завершать приложение.

Теперь мы добавим слот для сигнала "clicked" кнопки "Quit". Нажмите F4 для перехода в режим редактора сигналов и слотов. Нажмите кнопку "Quit" и отпустите кнопку мыши на свободном пространстве окна диалога. После того, как вы отпустите кнопку мыши, должно появиться окно "Настройка соединения" (Configure Connection) (Рисунок 8). Слева перечислены сигналы, которые может генерировать элемент графического интерфейса; справа перечислены слоты (проще говоря, действия), которые могут быть выполнены с элементом графического интерфейса QDialog.

Настройка соединения
Рисунок 8: Настройка соединения

В левом списке выберите clicked(), а в правом - close(). Таким образом, при нажатии кнопки "Quit" окно будет закрыто. Нажмите F3 для перехода в режим редактирования свойств элементов графического интерфейса. Кнопка "Count" тоже должна быть соединена со слотом. Выберите эту кнопку, нажмите правой кнопкой мыши и во всплывающем меню выберите пункт "Перейти к слоту..." ("Go to Slot"). В появившемся окне (Рисунок 9) "Переход к слоту" ("Go to Slot") будут перечислены сигналы, генерируемые данным элементом графического интерфейса.

Переход к слоту
Рисунок 9: Переход к слоту

Выберите сигнал clicked() и нажмите OK. В редакторе кода будет открыта функция void Dialog::on_pushButton_clicked() из файла dialog.cpp (Рисунок 10).

Функция слота
Рисунок 10: Функция слота

Отредактируйте этот код следующим образом:
void Dialog::on_pushButton_clicked()
{
	static int count;
	count++;
	ui->label->setText(QString::number(count));
}

В этом коде используется статическая переменная, значение которой увеличивается на 1 при каждом вызове функции, после чего значение преобразуется в строку QString и устанавливается в качестве текста строки. Нажмите Ctrl+R для сборки и запуска приложения (как на Рисунке 11).

Вывод
Рисунок 11: Вывод

Протестируйте приложение - нажмите кнопку "Count" и проверьте результат. Нажмите кнопку "Quit" для завершения работы приложения.

Дополнительные сигналы

Мы рассмотрели принцип использования механизма сигналов и слотов в Qt. Может возникнуть вопрос: возможно ли использование наших собственных сигналов? Да, это возможно. Давайте попробуем разобраться в этом вопросе при помощи кода, не связанного с графическим интерфейсом. (Мы описывали принцип создания приложений без графического интерфейса в предыдущей статье.) Создайте новый проект консольного приложения, выделите его название на левой панели и при помощи правой кнопки мыши вызовите всплывающее меню, в котором выберите пункт "Добавить новый..." ("Add New"). После этого в окне выберите из списков "C++" и "Класс C++" ("С++ class") (Рисунок 12).

Окно для выбора класса C++
Рисунок 12: Окно для выбора класса C++

Нажмите "Выбрать..." ("Choose"). Вам будет предложено ввести параметры нового класса (Рисунок 13). Назначьте имя классу и используйте QObject в качестве базового класса (это необходимо для использования механизма сигналов и слотов в классах, не относящихся к графическому интерфейсу). Завершите создание класса. В состав проекта будут добавлены файлы test.cpp и test.h.

Параметры нового класса
Рисунок 13: Параметры нового класса

Для начала рассмотрите код, а потом мы исследуем его.

Файл main.cpp:
#include <QtCore/QCoreApplication>
#include "test.h"
int main(int argc, char *argv[])
{
	QCoreApplication a(argc, argv);
	test t1,t2;
		QObject::connect(&t1,SIGNAL(valueChanged(int)), &t2,SLOT(changeValue(int)));
		QString name = "manoj@nxitsolutions.com";
		 t2.setName(name);
		t1.setValue(225);
	return a.exec();
}
Это файл test.h:
#ifndef TEST_H
#define TEST_H
#include <QObject>
class test : public QObject
{
	Q_OBJECT
public:
	explicit test(QObject *parent = 0);
	void setValue(int);
	void setName(QString &name);
signals:
	void valueChanged(int newValue);
public slots:
	void changeValue(int newValue);
private:
	int value;
	QString str;
};
#endif // TEST_H
А это файл test.cpp:
#include "test.h"
#include <QtCore>
test::test(QObject *parent) :
	QObject(parent)
{
}
void test::setName(QString &datastr){
	str = datastr;
}
void test::changeValue(int newValue)
{
	qDebug() < "Value " < newValue < "\nString = " < this->str;
}
void test::setValue(int newValue){
	emit valueChanged(newValue);
}

Теперь давайте исследуем код.

В класс test мы добавили две публичных функции - setValue и setName; один дополнительный сигнал - valueChanged; и две частные переменные - value и str. В функции setValue изменяется значение переменной int newValue и генерируется сигнал signal valueChanged при помощи ключевого слова emit.

Также мы можем добавлять аргументы к сигналу; в нашем случае мы мы передали значение переменной newValue. В файле main.cpp мы создаем два объекта test. После этого мы использовали функцию connect для соединения сигнала valueChanged(), генерируемого объектом t1 со слотом changeValue() объекта t2. Таким образом, обращение к функции setValue повлечет за собой генерацию сигнала объектом t1 и его захват объектом t2. Синтаксис функции, используемой для соединения сигнала со слотом представлен ниже:
QObject::connect(&t1,SIGNAL(valueChanged(int)), &t2,SLOT(changeValue(int)));
Скомпилируйте код и запустите программу; вы получите следующий вывод:
Value 225
String = "manoj@nxitsolutions.com"

А теперь немного теории.

Для использования сигналов и слотов, объект должен являться наследником класса QObject. Функция connect класса QObject осуществляет соединение двух объектов. Один объект генерирует сигнал, другой должен ответить на него обращением к обработчику (слоту). У функции connect() четыре аргумента: ссылка на первый объект, сигнал, ссылка на второй объект, и функция слота. Единственный сигнал может быть подключен к нескольким слотам и слот может вызываться несколькими сигналами. Все элементы графического интерфейса и размещения этих элементов также являются наследниками класса QObject. Ниже приведено несколько возможных вариантов исследования:
  1. Попробуйте использовать слот с большим или меньшим количеством аргументов, чем у сигнала и посмотрите, что получится в результате.
  2. Изучите сообщения об ошибках в случае наследования классов не от класса QObject.
  3. Сгенерируйте сигнал без подключения к какому-либо слоту.

Проведите эти исследования самостоятельно для того, чтобы узнать больше о поведении механизма сигналов и слотов. В следующей статье мы будем работать с классами Qt для создания графического интерфейса.