Глава 1 Основы создания приложений с использованием классов библиотеки Qt

Значительная часть классов библиотеки Qt использует отсутствующие в языке С++ средства, реализация которых требует применения дополнительного препроцессора – мета-объектного компилятора (MOC). Следовательно, прежде, чем программа, использующая классы Qt, будет передана препроцессору и компилятору языка С++, ее должен обработать MOC.

Разработчики библиотеки предусматривают несколько технологий создания программ с использованием библиотеки классов Qt. Всего поддерживаются три варианта:

· создание файлов программы в любых текстовых редакторах без специализированных сред и их компиляция, компоновка, запуск и отладка «вручную» в командном режиме операционной системы;

· создание программы «под Windows» в среде Microsoft Visual Studio (начиная с версии 2008 г.), при этом, как в ручном варианте, не поддерживается визуальное построение интерфейса, но используется возможность работы в текстовом редакторе Visual Studio, а также отладка программ с использованием встроенного в среду отладчика;

· создание программы в специализированной полноценной многоплатформенной среде Qt Creator, полностью обеспечивающей процесс создания приложений для наиболее распространенных операционных систем: Windows XP/Vista/Windows 7, Mac OS X, Linux, Solaris, HP-UX и других версий Unix.

Поддерживаются и различные комбинации перечисленных вариантов. Так фирма предоставляет отдельно от среды Qt Creator средство визуальной разработки интерфейсов приложений – Qt Designer. Это средство может использоваться как при работе вне сред программирования, так и на подготовительном этапе перед передачей проекта в Visual Studio.

1.1 Структура простейшей программы с Qt-интерфейсом

Создание интерфейса с применением средств библиотеки Qt продемонстрируем на программе, выдающей на экран традиционное приветствие «Hello!» или в русскоязычном варианте «Привет!».

1.1.1 Создание интерфейса из совокупности объектов библиотечных классов

Библиотека классов Qt предоставляет разработчику множество уже готовых интерфейсных компонентов, которые в Qt, как и в Linux, принято называть виджетами.

В простейшем случае виджеты Qt могут встраиваться в программный код без построения специального класса, объект которого соответствовал бы окну.

Традиционно интерфейс приложения Hello выдает на экран приветствие и ожидает сигнала завершения работы. В оконном варианте это предполагает использование некоторого элемента, который может визуализировать строку приветствия, например метки, и кнопки завершения. При нажатии на эту кнопку приложение должно завершать свою работу (рисунок 1.1).

Рисунок 1.1 – Вид окна приложения

Пример 1.1. Приложение Hello . Интеграция объектов классов Qt без построения специального класса окна.

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

Аналогично любой, построенной по объектной технологии и событийно управляемой программе, приложение Hello минимально должно включать два объекта:

· объект-приложение;

· объект-окно приложения.

Объект-приложение создается как объект класса QApplication. Объекты этого класса отвечают за создание и инициализацию главного окна, а также за запуск цикла обработки сообщений от операционной системы.

В качестве окна приложения будем использовать объект класса QWidget. Класс QWidget – базовый класс всех виджетов. Его объекты обладают свойствами контейнера, который управляет виджетами визуальных компонентов: метками, кнопками и др., размещенными в окне.

Кроме этого нам понадобится объект класса QLabel – меткавиджет, с помощью которого высвечивается текст приветствия, и объект класса QPushButton – кнопка – виджет, который используется для закрытия приложения.

Текст программы выглядит следующим образом:

#include <QApplication>

#include <QLabel>

#include <QPushbutton.h>

#include <QHBoxLayout>

 

int main(int argc,char *argv[])

{

QApplication app(argc,argv); // создание объекта-приложения

QWidget win; // создание объекта управления окном

win.setWindowTitle("Hello"); // изменение заголовка окна

 

QLabel *helloLabel=new QLabel("Hello!",&win); // создание метки

QPushButton *exitButton=new QPushButton("Close",&win);

// создание кнопки

QHBoxLayout *layout = new QHBoxLayout(&win); // создание

// менеджера компоновки для управления размещением метки и кнопки в окне win

layout->addWidget(helloLabel); // добавление метки к компоновщику

layout->addWidget(exitButton); // добавление кнопки к компоновщику

// связь сигнала нажатия кнопки с закрытием окна win

QObject::connect(exitButton,SIGNAL(clicked(bool)),

&win,SLOT(close()));

win.show(); // визуализация окна win

app.exec(); // запуск цикла обработки сообщений приложения

}

Помимо уже указанных объектов окна, метки и кнопки приложение включает также объект класса QHBoxLayout – горизонтальный менеджер компоновки, отвечающий за размещение и масштабирование подчиненных виджетов: метки и кнопки в окне приложения. Этот объект срезу при создании связывается с оконным объектом win:

QVBoxLayout *layout = new QVBoxLayout(&win);

А затем ему передается управление размерами и размещением метки и кнопки:

layout->addWidget(helloLabel);

layout->addWidget(exitButton);

Особого внимания заслуживает оператор (макрос) Qt connect, который связывает сигнал нажатия кнопки exitButton – clicked(bool) с его обработчиком:

QObject::connect(exitButton,SIGNAL(clicked(bool)),

&win,SLOT(close()));

Таким обработчиком – слотом окна win – является метод закрытия окна win – close(). По правилам оконных приложений этот метод обеспечивает не только закрытие окна, но и завершение приложения, если закрываемое окно – последнее.

Все объекты создаются в основной программе (рисунок 1.2, а), но при этом виджет окна назначается контейнером для всех остальных и управляет видимостью виджетов и памятью всех объектов Qt. Поэтому для визуализации окна с меткой и кнопкой достаточно вызвать метод Show() окна win, который обеспечит визуализацию, как самого окна, так и управляемых им виджетов (рисунок 1.2, б).

Рисунок 1.2 – Управление объектами Qt в процессе работы программы:

а – создание виджетов основной программой, б – управление видимостью виджетов через контейнер окна;

в – управление изменением размеров виджетов посредством менеджера компоновки; г – освобождение памяти через контейнер окна ()

После визуализации окна выполняется метод app.exec(), который запускается цикл обработки сообщений, организуя работу приложения.

Менеджер компоновки окна, как и само окно, является контейнером, но только для включенных в него виджетов метки и кнопки. Он управляет изменением размеров подчиненных виджетов при изменении размеров окна (рисунок 1.2, в).

После завершения программы для освобождения всей динамически распределенной памяти достаточно посредством оператора delete запросить освобождение памяти окна win. Деструктор этого объекта-контейнера автоматически освободит все управляемые им виджеты (рисунок 1.2, г) и прочие компоненты.

1.1.2 Разработка собственного класса окна приложения

Анализ диаграмм, приведенных на рисунке 1.1, показывает, что практически все управление компонентами окна, кроме их создания, реализуется программой не напрямую, а с использованием управляющего контейнера – объекта окна. Поэтому более логично и создание подчиненных компонентов возложить на виджет окна, для чего необходимо создать специальный класс окна.

Пример 1.2. Приложение Hello. Проектирование Qt интерфейса с использованием специального класса окна.

Класс окна обычно наследуется от одного из классов Qt. В нашем случае, как и в первом примере, наследование будем выполнять от класса QWidget (рисунок 1.3).

Рисунок 1.3 – Диаграмма классов приложения Hello

При наследовании управляемые окном виджеты Кнопка и Метка будут включены в проектируемый класс в качестве указателей на объекты соответствующих классов. Отношение между классами компонентов и проектируемым классом – наполнение.

Несколько более сложная ситуация с менеджером компоновки. Объект этого класса работает только в конструкторе класса окна и более нигде не используется. Поэтому целесообразно объявлять и создавать этот объект только в конструкторе проектируемого класса в качестве локальной переменной. Такое решение позволит сократить количество объектных полей класса окна и, соответственно, упростить его описание.

Компоновать приложение будем по схеме, рекомендуемой для программ на языке С++ (рисунок 1.4):

· файл hello.h будет содержать описание интерфейсного класса окна,

· файл hello.cpp – реализацию методов этого класса,

· файл main.cpp – основную программу.

Рисунок 1.4 – Диаграмма компоновки приложения Hello

Файл win.h с описанием класса окна:

#ifndef hello_h

#define hello_h

#include <QLabel>

#include <QPushButton>

 

class Win: public QWidget

{

QLabel *helloLabel;

QPushButton *exitButton;

public:

Win(QWidget *parent = 0);

};

#endif

Примечание. Для предотвращения повторной компиляции этого файла используется стандартный прием: в начале стоит проверка существования переменной win_h препроцессора. Если эта переменная задана, то файл уже был компилирован, если не задана – то переменная определяется, а файл компилируется.

Файл win.cpp содержит описание конструктора класса Win:

#include "hello.h"

#include <QHBoxLayout>

 

Win::Win(QWidget *parent):QWidget(parent)

{

setWindowTitle("Hello");

helloLabel=new QLabel("Hello!",this);

exitButton=new QPushButton("Exit",this);

QHBoxLayout *layout = new QHBoxLayout(this); // создание элемента

// компоновки для управления размещением метки и кнопки в окне win

layout->addWidget(helloLabel); // добавление метки к компоновщику

layout->addWidget(exitButton); // добавление кнопки к компоновщику

// связь сигнала нажатия кнопки и слота закрытия окна

connect(exitButton,SIGNAL(clicked(bool)),

this,SLOT(close()));

}

Файл main.cpp содержит основную программу:

#include "hello.h"

#include <QApplication>

 

int main(int argc, char *argv[])

{

QApplication app(argc, argv);

Win win(0);

win.show();

return app.exec();

}

Несмотря на то, что программа получилась более длинной, с точки зрения технологии она грамотнее построена и, следовательно, в ней проще разбираться, что особенно важно при разработке больших программ.

1.1.3 Создание русскоязычного интерфейса в Qt

Проблема неправильного отображения русских букв в интерфейсах программ на языке С++ связана с тем, что при вводе программы выводимые строки представлены в кодировке Windows-1251 (стандартная 8-битная кодировка русских версий Windows), а на экране при запуске программ в операционной системе Windows – в кодировке Unicode.

В кодировке Unicode все символы кодируются не 8-ми, а 16-ти битными кодами, что расширяет таблицу кодов более чем до 65 тыс. комбинаций и обеспечивает не только кодировку английских букв, но и символов национальных алфавитов, в том числе русского.

Преобразование в Unicode при запуске программы выполняется автоматически, из расчета, что исходный текст представлен в кодировке Windows-1252 (базовый западноевропейский вариант 8-ми битной кодировки). Таким образом, для символов английского алфавита, коды которых в обеих таблицах совпадают, преобразование проходит нормально, а для символов русского – с искажением.

Согласно концепции Qt все надписи формы хранятся сразу в кодировке Unicode в виде строк – объектов класса QString, поэтому с отображением этих надписей на экране проблем не возникает. Но преобразование выводимых строк в Unicode при их описании следует выполнить программно.

Для работы с разными, в том числе национальными кодировками в Qt определено семейство классов, одним из которых является класс QTextCodec. Объекты этого класса обеспечивают необходимые перекодировки и в том числе преобразование строк в Unicode в соответствии с используемой таблицей кодов. Таблица кодов русского языка 1251 может быть установлена при создании объекта класса QTextCodec:

QTextCodec *codec = QTextCodec::codecForName("Windows-1251");

Процесс перекодировки в Unicode осуществляется посредством метода:

QString QTextCodec::toUnicode(char *str);

например:

helloLabel = new QLabel(codec->toUnicode("Привет!"),this);

Пример 1.3. Приложение Hello. Создание русскоязычного интерфейса.

Создание интерфейса на русском языке по сравнению с программой примера 1.2 потребует незначительного изменения только файлов описания и реализации окна. Файл программы main.cpp при этом останется без изменения.

Файл win.h:

#ifndef win_h

#define win_h

#include <QTextCodec>

#include <QLabel>

#include <QPushButton>

 

class Win:public QWidget

{

private:

QTextCodec *codec; // перекодировщик

QLabel *helloLabel;

QPushButton *exitButton;

public:

Win(QWidget *parent = 0);

};

#endif

Файл win.cpp:

#include "win.h"

#include <QHBoxLayout>

Win::Win(QWidget *parent):QWidget(parent)

{

codec = QTextCodec::codecForName("Windows-1251");

setWindowTitle(codec->toUnicode("Приветствие"));

helloLabel = new QLabel(codec->toUnicode("Привет!"),this);

exitButton =

new QPushButton(codec->toUnicode("Выход"),this);

QHBoxLayout *layout = new QHBoxLayout(this);

layout->addWidget(helloLabel);

layout->addWidget(exitButton);

connect(exitButton,SIGNAL(clicked(bool)),

this,SLOT(close()));

}

После запуска программы получаем на экране окно с текстом на русском языке (рисунок 1.5).

Рисунок 1.5 – Интерфейс на русском языке

Примечание. Следует иметь в виду, что помимо средств создания национальных интерфейсов в Qt предусмотрены средства разработки интернациональных приложений с выбором языка интерфейса. С этой целью предлагаются специальные утилиты и приложение для составления переводов – Qt Linguist [1].

1.2 Особенности компиляции-сборки программ, использующих библиотеку Qt

При создании библиотеки Qt разработчики несколько расширили возможности языка С++, добавив к стандартному набору операторов и макросов С++ специальные макросы, которые обеспечивают передачу и обработку сигналов, хранение информации о типе времени выполнения и динамические свойства объектов и т.п.

Реализацию механизмов библиотеки Qt, отсутствующих в С++, обеспечивает специализированный препроцессор Qt – Meta-object Compiler – Мета-объектный компилятор (MOC). Этот препроцессор обрабатывает исходный текст программы, подставляя вместо специальных макросов Qt реализацию заказанных свойств на С++ (рисунок 1.6).

Как следует из схемы, MOC обрабатывает только заголовочные файлы, содержащие описание классов, наследуемых от классов Qt. В результате работы МОС в описание объявляемых классов включаются вспомогательные методы классов Qt. Реализация этих методов помещается в файл moс_<Имя класса>.cpp, который подключается к проекту посредством автоматически добавляемого #include. Тексты основных методов в файле реализации класса при этом не затрагивается.

После выполнения MOC на выходе получается исходный текст программы на «чистом» С++. Окончательная компиляция и сборка программы используемым компилятором C++ и компоновщиком, доступными в рамках платформы, где осуществляется компиляция-сборка.

 

 

Рисунок 1.6 – Схема сборки приложения при наличии в нем макросов Qt

1.2.1 Сборка приложений в командном режиме

Разработка приложений на многих платформах (таких как Linux, Solaris, HP-UX и др.) часто выполняется без специализированных сред. При этом программист создает текстовые модули программы в простейших текстовых редакторах типа Блокнота, а компиляция, сборка и отладка программ осуществляется командами вызова соответствующих программ: компилятора, компоновщика и (при наличии) отладчика, вводимыми непосредственно в командной строке консоли. С таким режимом работы целесообразно познакомиться и в Windows.

Как уже упоминалось выше помимо cpp- и h-файлов с текстом программы для создания приложения необходим файл проекта, который должен содержать сведения о компиляции и сборке программы. Операции по созданию файла проекта, а также его компиляции-сборки в соответствии с названием раздела выполним в командном (консольном) режиме.

Для работы в командном режиме необходимо, чтобы переменные окружения, указывающие местоположение используемых пакетов и тип компилятора, который будет использован при сборке Qt-проектов, были правильно определены. В Windows для правильного определения переменных окружения следует войти в консольный режим через команду, предусмотренную при установке Qt в меню Пуск операционной системы. Так для 64-разряной конфигурации VS 2017 выбираем пункт:

Пуск\Qt..\5.12.1\MSVC 2017(64-bit)\Qt5.12.1(MSVC 2017 64-bit).

После этого, чтобы облегчить работу в консольном режиме целесообразно вызвать файловый менеджер Far (или другой, например WinCommander). При этом понадобится указать полный путь к приложению. Так если менеджер Far установлен в папке Program Files (х86) на диске C, то команда должна выглядеть так:

″C:\Program Files (х86)\Far\Far.exe″

Примечание. Здесь и далее двойные кавычки при вводе команды необходимы, поскольку имя каталога Program Files (х86) состоит из нескольких слов, разделенных пробелами.

Для установки путей к программам среды Visual Studio 2017 следует выполнить командный файл vcvarsall.bat, если среда VS2017 установлена на диск C, то запуск командного файла на выполнение выглядит так:

″С:\Program Files (x86)\Microsoft Visual Studio\2017\

Community\VC\Auxiliary\Build\

vcvarsall.bat″ x86-amd64 .

Затем следует объявить текущей ту папку, в которой находятся cpp- и h- файлы программы. Для этого переходим в нее посредством Far или вводим в командную строку команду изменения директории, например:

cd С:\Examples\ .

Далее последовательность действий по компиляции-сборке приложения выглядит следующим образом.

1. Создание файла-проекта приложения. Для создания файла-проекта, включающего файлы текущей (!) директории, используют специальную консольную программу Qt – qmake, которой в качестве опции передается параметр -project:

qmake -project

Если имя папки, в которой находится программа, Hello, то в результате работы qmake в текущей папке появится файл проекта Hello.pro, со следующим содержимым:

TEMPLATE = app # тип исполняемого файла – .exe

TARGET = hello # имя создаваемого исполняемого файла

DEPENDPATH += . # дополнительные пути разрешения ссылок – не заданы

INCLUDEPATH += . # дополнительные пути поиска файлов – не заданы

# Input # комментарий – исходные файлы

HEADERS += win.h

SOURCES += main.cpp win.cpp

Содержимое файла-проекта определяет параметры процесса компиляции-сборки исполняемого файла из исходных файлов проекта и может включать переменные, перечисленные в таблице 1.1.

Таблица 1.1 – Переменные файла проекта

Переменная Оглавление
TEMPLATE Шаблон, используемый в проекте. Он определяет, что будет на выходе процесса сборки: приложение, библиотека или подключаемый модуль.
TARGET Имя результата сборки: приложения, библиотеки или модуля. По умолчанию совпадает с именем каталога.
DESTDIR Каталог, в который будет помещен исполняемый или бинарный файл, полученный в результате сборки. По умолчанию зависит от параметра CONFIG: CONFIG=debug – результат помещается в подкаталог debug текущего каталога, CONFIG=release – результат помещается в подкаталог release текущего каталога.
CONFIG Общие параметры настройки проекта, например создать отладочный (debug) или конечный (realease) варианты приложения. По умолчанию создается отладочный вариант приложения.
QT Qt-ориентированные параметры конфигурации, например указывающие на использование классов графического интерфейса пользователя (Graphics User Interface – GUI) или на использование средств OpenGL – OPENGL.
HEADERS Список заголовочных файлов (.h), используемых при сборке проекта.
SOURCES Список файлов с исходным кодом (.cpp), которые используются при сборке проекта.
FORMS Список файлов форм, полученных с использованием Qt Designer (.ui).
RESOURCES Список файлов ресурсов (.rc), которые включаются в конечный проект (пиктограммы, картинки и т.п.).
DEF_FILE Файл .def, который линкуется вместе с приложением (только для Windows).
RC_FILE Файл ресурса для приложения (только для Windows).

 

В простейших случаях автоматически полученный файл проекта можно использовать при отладке приложения. Однако если при проектировании интерфейса были использованы макросы Qt, например QOBJECT, то в файл проекта необходимо добавить:

QT += gui widgets # используемые средства Qt: графический интерфейс

Если же необходимо создать итоговый вариант реализации, файл проекта надо отредактировать так:

TEMPLATE = app # тип исполняемого файла – .exe

TARGET = Hello # имя исполняемого файла – Hello

QT += gui widgets # используемые средства Qt: графический интерфейс

CONFIG += release # создание итогового варианта реализации

# Input # комментарий – исходные файлы

HEADERS += win.h

SOURCES += main.cpp win.cpp

2. Создание файла управления компиляцией-сборкой. После создания и редактирования файла проекта Hello.pro повторно вызываем процедуру qmake, передавая ей в качестве параметра имя файла проекта:

qmake Hello.pro

Теперь qmake на базе файла проекта формирует файл Makefile, определяющий фактический порядок компиляции-сборки программы, местоположение компилятора и необходимых библиотек.

Если все прошло нормально, то в текущей директории появится файл Makefile, два подкаталога debug и release и несколько вспомогательных файлов.

3. Компиляция-сборка приложения. Не меняя текущей директории, вводим команду вызова процедуры компиляции-сборки make:

· nmake – если используется компилятор-компоновщик Microsoft Visual C++;

· mingw32-make – для вызова компилятора mingw.

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

set PATH=C:\Program Files (x86)\Microsoft Visual Studio 9.0\

VC\bin;%PATH%

Результат сборки программы – приложение Hello.exe и промежуточные файлы процесса компиляции/сборки, которые в зависимости от задания будут добавлены в каталог debug или release.

4. Выполнение программы. Запускаем программу Hello.exe и на экране получаем окно приложения. При щелчке мышкой по кнопке Close или Выход приложение завершает работу.

Примечание. В процессе работы приложению Qt необходимы несколько динамических библиотек, которые должны быть доступны в путях автовызова, устанавливаемых системной переменной Path, или могут быть скопированы в директорию приложения ...\release.

1.2.2 Сборка Qt-программ в среде Microsoft Visual Studio

В качестве альтернативы компиляции-сборке приложений Qt в командном режиме можно предложить создание приложений с использованием среды Microsoft Visual Studio 2008 и более поздние. Для этого необходимо скачать и установить на компьютер специальный дистрибутив – Qt-библиотеку для Visual Studio и плагин для среды (см. приложение А).

После установки плагина Qt в Visual Studio при создании приложений с использованием пункта меню:

Файл\Создать\Проект\Тест\

становятся доступны шаблоны приложений Qt: Qt ActiveQt Server, Qt Class Library, Qt Console Application, Qt Designer Custom Widget и Qt Gui Application.

На этапе обучения созданию приложений с графическим интерфейсом мы будем использовать заготовку проекта последнего вида.

При этом нам предлагается выбрать базовый класс для построения окна: QWidget (простое окно без виджетов), QMainWindow (главное окно с меню) или QDialig (окно диалога). В зависимости от нашего выбора Мастер создает заготовку Qt-приложения с заготовками следующих файлов:

QtGuiApplication1.h – для объявления/описания класса окна;

QtGuiApplication1.cpp – для описания методов этого класса;

QtGuiApplication1.ui – для проектирования внешнего вида окна в QtDesiner;

QtGuiApplication1.qrc – для ресурсов проекта;

main.cpp – для заготовки основной программы.

Если некоторые из перечисленных файлов вам не нужны, то потом их можно удалить из проекта и с диска.

Всю дальнейшую работу по созданию, компиляции, сборке и отладке Qt-приложений можно выполнять в среде Visual Studio.

Примечание. Открывать Qt-приложения, созданные другими средствами, следует, используя пункт меню:

Qt VS Tools\Open Qt Project File (.pro) …

1.2.3 Qt Designer. Быстрая разработка прототипов интерфейсов

Qt Designer – программа визуального проектирования интерфейса пользователя. Результатом работы этой программы является файл XML-описания формы, имеющий расширение .ui – <Имя формы>.ui (рисунок 1.7).

Рисунок 1.7 – Схема компиляции-сборки приложения с формами интерфейса, созданными в Qt Designer

Файлы, созданные с использованием Qt Designer в дальнейшем дополнительно обрабатываются специальным компилятором UIC (User Interface Compiler – Компилятор пользовательского интерфейса), который формирует код программы на С++ из его XML-описания. Результатом компиляции является файл ui_<Имя формы>.h. Этот файл содержит описание метода setupUi, использующего классы Qt и обеспечивающего создание разработанной формы.

Автоматически созданный файл вместе с описанием класса формы передаются MOC для реализации необходимых дополнительных функций библиотеки Qt.

После этого файлы приложения обрабатываются компилятором и компоновщиком С++. В результате – создается файл приложения.

Помимо конструирования внешнего вида окна приложения Qt Designer позволяет:

· запрограммировать предусмотренные Qt (!) аспекты поведения формы и ее компонентов;

· связать метки (объекты класса QLabel) с другими виджетами так, что при щелчке мышкой на метке фокус ввода будет передаваться на ассоциированный виджет;

· определить порядок передачи фокуса ввода виджетам формы при нажатии клавиши Tab.

Примечание. Следует подчеркнуть, что описать поведение виджетов можно лишь в тех случаях, когда в приложении задействованы предусмотренные в классах виджетов сообщения сигналы и реакции на них – слоты. Новые сигналы и слоты можно объявлять при создании потомков классов виджетов специальными операторами Qt (см. раздел 2.3).

Описание всех перечисленных связей виджетов – также на языке XML – добавляется в файл формы с расширением .ui.

Исполняемый файл Qt Designer designer.exe может быть запущен как из консольного окна, так и непосредственно из Windows.

При запуске на экране появляется главное окно приложения и перед ним диалоговое окно Новая форма (рисунок 1.8).

Рисунок 1.8 – Вид конструктора форм при запуске программы

В диалоговом окне предлагается выбрать шаблон для формы окна. В качестве таких шаблонов могут использоваться объекты классов QWidget, QDialog и QMainWindow. Затем, уже в Designer выполняют проектирование интерфейса.

Выполним визуальное проектирование формы интерфейса приложения Hello, рассмотренного в разделе 1.1.

Пример 1.4. Приложение Hello. Создание с использованием программы визуального проектирования формы.

Создание главного окна приложения. В качестве основы формы будем использовать объект класса QWidget, как в предыдущем примере. Соответственно в ответ на запрос Designer выбираем шаблон (templates) Widget и нажимаем кнопку Create. В результате создается заготовка окна, озаглавленная Form – untitled, где Form – имя объекта класса QWidget по умолчанию, untitled (безымянный) – означает, что файл создаваемой формы приложения пока не имеет имени.

На эту форму с левой панели Widget box перетаскиваем мышкой два виджета Label и PushButton (рисунок 1.9).

Рисунок 1.9 – Основные панели дизайнера и добавление виджетов на форму

Полученную форму сохраняем под именем form.ui. Для этого используется пункт меню Файл\Сохранить как…

Далее, используя панели Инспектора объектов и Редактора свойств, выбираем объекты и присваиваем им новые имена, меняя свойство objectName:

QWidget: objectName = Form ® objectName = win;

QPushButton: objectName = pushButton ® bjectName = button.

Также с помощью Редактора свойств меняем заголовки виджетов (свойство text):

label: text = ʺHello!ʺ; button: text = ʺCloseʺ.

Управление расположением и размерами виджетов. Также как и при создании интерфейса вручную для управления размещением виджетов на форме Qt Designer использует компоновщики. Для добавления компоновщика компонуемые виджеты должны быть выделены, что можно сделать, щелкая мышкой по виджетам при нажатой клавиши Ctrl.

Добавление компоновщиков и связывание с ними виджетов осуществляется выбором пунктов меню:

· Форма\Скомпановать по горизотали – компоновать по горизонтали,

· Форма\Скомпановать по вертикали – компоновать по вертикали,

· Форма\Скомпоновать по сетке – компоновать по сетке,

или нажатием соответствующих кнопок на панели компонентов дизайнера.

Обратите внимание, что связывание главного компоновщика с окном происходит, если выбрать горизонтальную или вертикальную компоновку при отсутствии выделенных виджетов.

Компоновку окна приложения выполняем следующим образом:

· label и button – компонуем по вертикали;

· окно приложения (при отсутствии выбранных виджетов) – компонуем по горизонтали.

После настройки виджетов и выполнения компоновки получаем готовую форму (рисунок 1.10), окончательный вариант которой не забываем сохранить, используя пункт меню Файл/Сохранить.

Рисунок 1.10 – Вид окна дизайнера после компоновки формы

Связывание сигналов и слотов. Как уже говорилось выше, кроме визуального конструирование вида окон, Qt Designer позволяет связать заранее предусмотренные сигналы виджетов с такой же заранее предусмотренной реакцией других виджетов на эти сигналы. Для этого необходимо переключиться в режим Редактор сигналов/слотов, выбрав пункт меню Правка\Изменение Сигналов/Слотов.

Указание виджетов, между сигналом и слотом которых устанавливается связь, выполняется визуально: щелкаем левой клавишей мышки по виджету кнопки и, не отпуская левой клавиши, переносим указатель мышки на свободное место окна (рисунок 1.11). Выбранные виджеты связываются красной линией, после чего открывается окно Настройка соединения, в котором выбираем слева сигнал clicked(), а справа слот close(). (Для того, чтобы справа появились доступные слоты необходимо внизу окна выбрать Показывать сигналы и слоты, унаследованные от QWidget. Для завершения операции необходимо нажать на кнопку OK.

Рисунок 1.11 – Вид окна при связывании сигнала от кнопки с закрытием окна

После закрытия вспомогательного окна установленные связи на форме маркируются выбранными сигналом и слотом (рисунок 1.12).

Рисунок 1.12 – Маркировка связей «Сигнал – слот» в дизайнере

Предварительный просмотр формы. QtDesigner позволяет просмотреть полученную форму. Для этого необходимо выбрать пункт меню Форма\Предпросмотр в.... Далее выбирается стиль предпросмотра. В режиме предварительного просмотра форма выглядит и реагирует на действия пользователя так, как это будет происходить во время работы программы (рисунок 1.13).

Рисунок 1.13 – Предварительный просмотр сконструированной формы

Полученную и проверенную форму сохраняем еще раз и переходим к созданию собственно приложения.

Описание класса окна. Приложение в соответствии со схемой работы Qt Designer должно включать класс окна. Этот класс может строиться двумя способами:

1) как наследуемый от двух классов:

· класса, на базе объекта которого строится окно приложения,

· класса, описание которого получается автоматически при обработке созданного Qt Designer файла формы компилятором UIC;

2) как композиция или агрегация тех же классов.

Во втором случае объект класса, наследуемого от класса Qt, включает поле автоматически созданного класса или содержит указатель на него ( рисунок 1.14).

Рисунок 1.14 – Возможные варианты подключения автоматически созданного класса образа окна:

а – множественное наследование; б – композиция; в – наполнение (агрегация)

Вариант множественного наследования удобнее при написании программы, поскольку при обращении к полям и методам родительского класса не требуется дополнительно указывать имя поля (обычного или указателя), поэтому желательно использовать именно его.

При использовании множественного наследования описание класса окна нашего приложения в файле Win.h должно выглядеть так:

#ifndef win_H

#define win_H

#include <QtWidgets/QWidget>

#include "ui_form.h" // заголовок сгенерированный UIC

class Win : public QWidget, public Ui::win

{

Q_OBJECT

public:

Win( QWidget *parent = Q_NULLPTR);

};

#endif

Класс win – класс, автоматически созданный при работе Qt Designer и описанный в файле ui_form.h, Ui – имя адресного пространства, объявленного Qt Designer. Одним из методов этого класса является метод setupUi, который обеспечивает изображение и заданную реакцию формы. Конструктор класса окна, описываемый в файле реализации Win.cpp, должен вызывать этот метод для построения окна:

#include <Win.h>

Win::Win(QWidget *parent):QWidget(parent)

{

setupUi(this); // конструирование формы

};

После этого основной программе остается только создать объект-приложение и объект-окно, визуализировать форму и ее виджеты и запустить цикл обработки сообщений:

#include "win.h"

#include <QtWidgets/QApplication>

int main(int argc, char *argv[])

{

QApplication app(argc, argv);

Win w;

w.show();

return app.exec(); // запуск цикла обработки сообщений

}

Компиляция-сборка программы в этом случае может осуществляться в командном режиме, как указано в разделе 1.3, или с помощью среды Microsoft Visual Studio, как предлагается в разделе 1.4.

Интересно посмотреть автоматически созданное описание класса окна в файле ui_form.h:

#ifndef UI_FORM_H // защита от повторной компиляции

#define UI_FORM_H

#include <QtCore/QVariant> // подключение заголовков файлов Qt

#include <QtWidgets/QApplication>

#include <QtWidgets/QFormLayout>

#include <QtWidgets/QLabel>

#include <QtWidgets/QPushButton>

#include <QtWidgets/QVBoxLayout>

#include <QtWidgets/QWidget>

QT_BEGIN_NAMESPACE // метка начала пространства имен

 

class Ui _ win // описание базового класса для класса окна

{

public:

QFormLayout *formLayout; // горизонтальный компоновщик

QVBoxLayout *verticalLayout; // вертикальный компоновщик

QLabel *label; // метка

QPushButton *Button; // кнопка

void setupUi(QWidget *win) // метод конструирования формы

{

if (win->objectName().isEmpty())

win->setObjectName(QString::fromUtf8("win"));

win->resize(254, 96);

formLayout = new QFormLayout(win);

formLayout->setSpacing(6);

formLayout->setContentsMargins(11, 11, 11, 11);

formLayout->

setObjectName(QString::fromUtf8("formLayout"));

verticalLayout = new QVBoxLayout();

verticalLayout->setSpacing(6);

verticalLayout->

setObjectName(QString::fromUtf8("verticalLayout"));

label = new QLabel(win);

label->setObjectName(QString::fromUtf8("label"));

 

verticalLayout->addWidget(label);

 

button = new QPushButton(win);

button->setObjectName(QString::fromUtf8("button"));

verticalLayout->addWidget(button);

formLayout->setLayout(0, QFormLayout::LabelRole,

verticalLayout);

retranslateUi(win);

QObject::connect(button, SIGNAL(clicked()),

win, SLOT(close()));

QMetaObject::connectSlotsByName(win);

} // setupUi

 

void retranslateUi(QWidget *win)

{

win->setWindowTitle(QApplication::translate("win",

"Win", nullptr));

label->setText(QApplication::translate("win",

"\"Hello!\"", nullptr));

button->setText(QApplication::translate("win",

"Close", nullptr));

} // retranslateUi

 

};

namespace Ui {

class win: public Ui_win {};

}

QT_END_NAMESPACE // метка конца пространства имен Ui

#endif

Qt Designer автоматически построил текст, близкий к тексту программы из раздела 1.1. Однако этот текст существенно длиннее и сложнее организован, что вызвано необходимостью предусмотреть в шаблоне различные варианты. Так, например, для организации смены языка интерфейса в процессе работы программы все строки, которые должны быть переведены, собраны в одном специальном методе retranslateUi().

Избыточность кода, генерируемого Qt Designer, является причиной того, что данный пакет обычно используют для быстрого создания прототипа интерфейса, а для конечной реализации интерфейсы создают вручную с использованием классов Qt.

1.2.4 Интегрированная среда разработки Qt Creator