Начало работы с Qt Widgets
В этом разделе мы изучим основы Qt, реализовав простое приложение «Блокнот» с использованием C++ и модуля Qt Widgets. Приложение представляет собой небольшой текстовый редактор, который позволяет создавать текстовый файл, сохранять его, печатать, повторно открывать и редактировать. Также вы можете задать шрифт.
Вы можете найти исходные файлы приложения «Блокнот» в репозитории qtdoc в каталоге snippets/widgets-tutorial/notepad. Вы можете скачать исходники Qt 5 с сайта Qt Project или установить их как часть Qt 5.
Создание проекта «Блокнот»
Настройка нового проекта в Qt Creator облегчается с помощью мастера, который пошагово проведет вас через процесс создания проекта. Мастер запросит у вас необходимые настройки для этого типа проекта и создаст проект.
Чтобы создать проект «Блокнот», выберите Файл > Создать новый файл или проект > Приложения > Приложение Qt Widgets > Выбрать и следуйте инструкциям мастера. В диалоговом окне Информация о классе введите Notepad в качестве имени класса и выберите QMainWindow в качестве базового класса.
Мастер Приложение Qt Widgets создает проект, содержащий главный исходный файл и набор файлов, определяющих пользовательский интерфейс (виджет «Блокнот»):
- notepad.pro – файл проекта.
- main.cpp – главный исходный файл приложения.
- notepad.cpp – исходный файл класса notepad для виджета «Блокнот».
- notepad.h – заголовочный файл класса notepad для виджета «Блокнот».
- notepad.ui – форма пользовательского интерфейса для виджета «Блокнот».
Файлы с расширениями .cpp, .h и .ui содержат необходимый шаблонный код, который позволит вам скомпилировать и запустить проект. Файл .pro завершен. В следующих разделах мы более подробно рассмотрим содержимое этих файлов.
Дополнительная информация
| О | Здесь |
|---|---|
| Использование Qt Creator | Qt Creator |
| Создание других типов приложений с помощью Qt Creator | Учебники по Qt Creator |
Главный исходный файл
Мастер генерирует следующий код в файле main.cpp:
#include "notepad.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication EditorApp(argc, argv);
Notepad Editor;
Editor.show();
return EditorApp.exec();
} Мы пройдемся по коду построчно. Следующие строки включают заголовочные файлы для виджета «Блокнот» и QApplication. Все классы Qt имеют заголовочный файл, названный так же, как и класс.
#include "notepad.h" #include <QApplication>
Следующая строка определяет функцию main, которая является точкой входа для всех приложений, основанных на C и C++:
int main(int argc, char *argv[])
{ Следующая строка создает объект QApplication. Этот объект управляет ресурсами всего приложения и необходим для запуска любой программы Qt, использующей Qt Widgets. Он создаёт объект приложения с argc аргументами командной строки, запущенными в argv. (Для приложений графического интерфейса, не использующих Qt Widgets, можно использовать QGuiApplication.)
QApplication EditorApp(argc, argv);
Следующая строка создает объект Notepad. Это объект, для которого мастер создал класс и файл пользовательского интерфейса. Пользовательский интерфейс содержит визуальные элементы, которые называются widgets в Qt. Примерами виджетов являются поля редактирования текста, полосы прокрутки, метки и радиокнопки. Виджет также может быть контейнером для других виджетов; например, диалоговое окно или главное окно приложения.
Notepad Editor;
Следующая строка отображает виджет «Блокнот» на экране в собственном окне. Виджеты также могут выполнять функции контейнеров. Примером является QMainWindow, который часто содержит несколько типов виджетов. Виджеты по умолчанию не отображаются; функция show() делает виджет видимым.
Editor.show();
Следующая строка заставляет QApplication войти в цикл обработки событий. При запуске приложения Qt генерируются события и отправляются виджетам приложения. Примерами событий являются нажатия мыши и нажатия клавиш.
return EditorApp.exec();
Дополнительная информация
| О | Здесь |
|---|---|
| Виджеты и геометрия окна | Окна и диалоговые виджеты |
| События и обработка событий | Система обработки событий |
Проектирование пользовательского интерфейса
Мастер генерирует определение пользовательского интерфейса в формате XML: notepad.ui. При открытии файла notepad.ui в Qt Creator он автоматически открывается в интегрированном Qt Designer.
При компиляции приложения Qt Creator запускает компилятор пользовательского интерфейса Qt (uic), который считывает файл .ui и создаёт соответствующий заголовочный файл C++, ui_notepad.h.
Использование Qt Designer
Мастер создаёт приложение, использующее QMainWindow. У него есть собственная компоновка, в которую можно добавить строку меню, виджеты-доки, панели инструментов и строку состояния. Центральная область может быть занята любым типом виджета. Мастер помещает туда виджет «Блокнот».
Для добавления виджетов в Qt Designer:
- В режиме редактирования Qt Creator дважды щелкните файл notepad.ui в представлении «Проекты», чтобы открыть файл в интегрированном Qt Designer.
- Перетащите виджет «Поле редактирования текста» (QTextEdit) на форму.
- Нажмите Ctrl+A (или Cmd+A), чтобы выбрать виджеты, и нажмите Разместить вертикально (или нажмите Ctrl+L), чтобы применить вертикальную компоновку (QVBoxLayout).
- Нажмите Ctrl+S (или Cmd+S), чтобы сохранить изменения.
Пользовательский интерфейс теперь выглядит следующим образом в Qt Designer:
Вы можете просмотреть сгенерированный XML-файл в редакторе кода:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Notepad</class>
<widget class="QMainWindow" name="Notepad">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>524</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Notepad</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextEdit" name="textEdit"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menuBar">
... Следующая строка содержит объявление XML, которое указывает версию XML и кодировку символов, используемые в документе:
<?xml version="1.0" encoding="UTF-8"?>
Остальная часть файла определяет элемент ui, который определяет виджет «Блокнот»:
<ui version="4.0">
Файл пользовательского интерфейса используется совместно с заголовочным и исходным файлом класса Notepad. В следующих разделах мы рассмотрим остальную часть файла пользовательского интерфейса.
Заголовочный файл Notepad
Мастер сгенерировал заголовочный файл для класса Notepad, содержащий необходимые #include, конструктор, деструктор и объект Ui. Файл выглядит следующим образом:
#include <QMainWindow>
namespace Ui {
class Notepad;
}
class Notepad : public QMainWindow
{
Q_OBJECT
public:
explicit Notepad(QWidget *parent = 0);
~Notepad();
private:
Ui::Notepad *ui;
}; Следующая строка включает QMainWindow, который предоставляет главное окно приложения:
#include <QMainWindow>
Следующие строки объявляют класс Notepad в пространстве имён Ui, которое является стандартным пространством имён для классов пользовательского интерфейса, сгенерированных из файлов .ui инструментом uic:
namespace Ui {
class Notepad;
} Объявление класса содержит макрос Q_OBJECT. Он должен стоять первым в определении класса и объявляет наш класс как QObject. Естественно, он также должен наследоваться от QObject. QObject добавляет несколько возможностей к обычному классу C++. В частности, имя класса и имена слотов можно запросить во время выполнения. Также возможно запросить типы параметров слота и вызвать его.
class Notepad : public QMainWindow
{
Q_OBJECT Следующие строки объявляют конструктор, имеющий аргумент по умолчанию, называемый parent. Значение 0 указывает, что у виджета нет родителя (это виджет верхнего уровня).
public:
explicit Notepad(QWidget *parent = 0); Следующая строка объявляет виртуальный деструктор для освобождения ресурсов, полученных объектом за время его жизненного цикла. Согласно соглашению об именовании C++, деструкторы имеют то же имя, что и класс, к которому они относятся, с префиксом тильда (~). В QObject деструкторы виртуальные, чтобы гарантировать, что деструкторы производных классов вызываются должным образом, когда объект удаляется через указатель на базовый класс.
~Notepad();
Следующие строки объявляют член-переменную, которая является указателем на класс пользовательского интерфейса Notepad. Член-переменная связана с определенным классом и доступна для всех его методов.
private:
Ui::Notepad *ui; Исходный файл Notepad
Исходный файл, сгенерированный мастером для класса Notepad, выглядит следующим образом:
#include "notepad.h"
#include "ui_notepad.h"
Notepad::Notepad(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Notepad)
{
ui->setupUi(this);
}
Notepad::~Notepad()
{
delete ui;
} Следующие строки включают заголовочный файл класса Notepad, сгенерированный мастером, и заголовочный файл пользовательского интерфейса, сгенерированный инструментом uic:
#include "notepad.h" #include "ui_notepad.h"
Следующая строка определяет конструктор Notepad:
Notepad::Notepad(QWidget *parent) :
Следующая строка вызывает конструктор QMainWindow, который является базовым классом для класса Notepad:
QMainWindow(parent),
Следующая строка создает экземпляр класса пользовательского интерфейса и присваивает его члену ui:
ui(new Ui::Notepad)
Следующая строка настраивает пользовательский интерфейс:
ui->setupUi(this);
В деструкторе мы удаляем ui:
Notepad::~Notepad()
{
delete ui;
} Для того, чтобы поле редактирования текста занимало весь экран, мы добавляем setCentralWidget в главное окно.
Notepad::Notepad(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::Notepad)
{
ui->setupUi(this);
this->setCentralWidget(ui->textEdit);
} Файл проекта
Мастер генерирует для нас следующий файл проекта, notepad.pro:
#-------------------------------------------------
#
# Project created by QtCreator 2017-07-10T14:20:07
#
#-------------------------------------------------
QT += core gui printsupport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Notepad
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp\
notepad.cpp
HEADERS += notepad.h
FORMS += notepad.ui
RESOURCES += \
notepad.qrc Файл проекта определяет имя приложения и qmake шаблон для генерации проекта, а также исходные, заголовочные и файлы пользовательского интерфейса, включенные в проект.
Вы также можете использовать qmake's -project вариант для генерации файла .pro. Однако в этом случае вам нужно помнить, чтобы добавить строку QT += widgets в сгенерированный файл, чтобы связаться с модулем Qt Widgets.
Дополнительная информация
| О | Здесь |
|---|---|
| Использование Qt Designer | Справочник Qt Designer |
| Компоновки | Управление компоновкой, Виджеты и компоновки, Примеры компоновок |
| Виджеты, которые поставляются с Qt | Галерея виджетов Qt |
| Главные окна и классы главных окон | Главное окно приложения, Примеры главного окна |
| QObjects и модель объектов Qt (необходимо понять Qt) | Модель объектов |
| qmake и система сборки Qt | Справочник qmake |
Добавление взаимодействия с пользователем
Чтобы добавить функциональность редактору, мы начнем с добавления пунктов меню и кнопок на панели инструментов.
Нажмите на «Ввести здесь» и добавьте параметры «Новый», «Открыть», «Сохранить», «Сохранить как», «Печать» и «Выход». Это создаст 5 строк в редакторе действий ниже. Чтобы связать действия со слотами, щелкните правой кнопкой мыши действие и выберите «Перейти к слоту» > «triggered()», а затем заполните код для этого слота.
Если мы также хотим добавить действия в панель инструментов, мы можем назначить значок каждому QAction, а затем перетащить QAction на панель инструментов. Вы назначаете значок, введя имя значка в свойстве «Значок» соответствующего действия. Когда QAction перетащен на панель инструментов, щелчок по значку запустит связанный слот.
Заполните метод on_actionNew_triggered():
void Notepad::on_actionNew_triggered()
{
currentFile = "";
ui->textEdit->setText("");
} current_file — это глобальная переменная, содержащая файл, который в настоящее время редактируется. Она определена в частной части notepad.h:
private:
Ui::Notepad *ui;
QString CurrentFile; setText("") очищает буфер текста.
Открытие файла
В notepad.ui щелкните правой кнопкой мыши actionOpen и выберите Go to slot
Заполните метод on_actionOpen_triggered().
void Notepad::on_actionOpen_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open the file");
QFile file(fileName);
currentFile = fileName;
if (!file.open(QIODevice::ReadOnly | QFile::Text)) {
QMessageBox::warning(this,"..","File not opened.");
return;
}
QTextStream in(&file);
QString text = in.readAll();
ui->textEdit->setText(text);
file.close();
} QFileDialog::getOpenFileName открывает диалоговое окно, позволяющее выбрать файл. Объект QFile myfile имеет выбранный file_name в качестве параметра. Мы также сохраняем выбранный файл в глобальную переменную current_file для последующего использования. Мы открываем файл с file.open как текстовый файл только для чтения. Если его невозможно открыть, выводится предупреждение, и программа останавливается.
Мы определяем QTextStream instream для параметра myfile. Содержимое файла myfile копируется в QString text. setText(text) заполняет буфер нашего редактора содержимым text.
section2 Сохранение файла
Мы создаём метод для сохранения файла аналогично методу для Открытия файла, щелкнув правой кнопкой мыши actionSave и выбрав Go to Slot.
void Notepad::on_actionSave_triggered()
{
QFile file(currentFile);
if (!file.open(QIODevice::WriteOnly | QFile::Text)) {
QMessageBox::warning(this,"..","No file opened. Use Save As");
return;
}
QTextStream out(&file);
QString text = ui->textEdit->toPlainText();
out << text;
file.flush();
file.close();
} Объект QFile myfile связан с глобальной переменной current_file, переменной, содержащей файл, с которым мы работали. Если мы не можем открыть myfile, выводится сообщение об ошибке, и метод останавливается. Мы создаём QTextStream outstream. Содержимое буфера редактора преобразуется в обычный текст и записывается в outstream.
section2 Сохранение файла с Save as
void Notepad::on_actionSave_as_triggered()
{
QString fileName = QFileDialog::getSaveFileName(this, "Save as");
QFile file(fileName);
currentFile = fileName;
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this,"..","File not opened.");
return;
}
QTextStream out(&file);
QString text = ui->textEdit->toPlainText();
out << text;
file.flush();
file.close();
} Это та же процедура, что и для Saving a file, единственное отличие заключается в том, что здесь вам необходимо ввести новое имя файла для создания файла.
Печать файла
Если вы хотите использовать функции печати, вам нужно добавить printsupport в файл проекта:
QT += core gui printsupport
Мы объявляем объект QPrinter с именем printer. Мы запускаем диалоговое окно принтера и сохраняем выбранный принтер в объекте printer. Если мы щелкнули по Cancel и не выбрали принтер, методы возвращают значение. Фактическая команда печати выполняется с помощью ui->textEdit->print с нашим объектом QPrinter в качестве параметра.
Выбор шрифта
void Notepad::on_actionFont_triggered()
{
bool fontSelected;
QFont font = QFontDialog::getFont(&fontSelected, this);
if (fontSelected) {
ui->textEdit->setFont(font);
}
} Мы объявляем булево значение, указывающее, выбрали ли мы шрифт с помощью QFontDialog. В таком случае мы устанавливаем шрифт с помощью ui->textEdit->setFont(myfont).
Копирование, вырезание, вставка, отмена, повторение
Если вы выделили текст и хотите скопировать его в буфер обмена, вызывается соответствующий метод ui->textEdit. То же самое касается вырезания, вставки, отмены и повторения.
В этой таблице показано имя метода, который нужно использовать.
| Задача | Вызываемый метод |
|---|---|
| Копирование | ui->textEdit->copy() |
| Вырезание | ui->textEdit->cut() |
| Вставка | ui->textEdit->paste() |
| Отмена | ui->textEdit->undo() |
| Повторение | ui->textEdit->redo() |
В этом проекте содержатся следующие файлы:
- {main.cpp}
- {notepad.cpp}
- {notepad.h}
- {notepad.pro}
- {notepad.ui}
Дополнительная информация
| О | Здесь |
|---|---|
| MDI-приложения | QMdiArea, Пример MDI |
| Файлы и устройства ввода-вывода | QFile, QIODevice |
| tr() и международная локализация | Руководство Qt Linguist, Написание исходного кода для перевода, Международная локализация с Qt |
Сборка и запуск Блокнота
Теперь, когда у вас есть все необходимые файлы, выберите Сборка > Собрать проект Блокнот, чтобы собрать и запустить приложение. Qt Creator использует qmake и make для создания исполняемого файла в каталоге, указанном в настройках сборки проекта, и запускает его.
Сборка и запуск из командной строки
Чтобы собрать приложение из командной строки, переключитесь на каталог, в котором находится файл .cpp приложения, и добавьте файл проекта (с расширением .pro), описанный ранее. Затем следующие команды оболочки собирают приложение:
qmake make (or nmake on Windows)
Команды создают исполняемый файл в каталоге проекта. Инструмент qmake считывает файл проекта и генерирует Makefile с инструкциями по сборке приложения. Затем инструмент make (или инструмент nmake) считывает Makefile и генерирует двоичный исполняемый файл.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.9/gettingstartedqt.html