Это руководство является введением в программирование графических интерфейсов на Qt.
Здесь мы изучим несколько базовых компонентов, включая:
- Виджеты и менеджеры слоев
- Классы-контейнеры
- Сигналы и слоты
- Устройства ввода и вывода
Если вы только что начали изучать Qt, мы рекомендуем прочитать введение в программирование на Qt.
Несмотря на то, что эта маленькая программа не выглядит, как полноценное графическое приложение, в нем есть много базовых элементов, которые используются в более сложных программах.
Разработка пользовательского интерфейса
Сейчас мы создадим базовый графический интерфейс для адресной книги, который будет состоять из надписей и текстовых полей. Ниже представлен скриншот того, что должно получиться.
Нам необходимы два объекта QLabel — nameLabel
и addressLabel
, а также два текстовых поля: nameLine
— объект класса QLineEdit и addressText
— объект QTextEdit. Текстовые поля нужны для того, чтобы пользователь мог вводить имена и адреса своих контактов. Позиции используемых виджетов отмечены на рисунке ниже.
Для реализации адресной книги используются три файла:
addressbook.h
— определение класса AddressBookaddressbook.cpp
— реализация класса AddressBookmain.cpp
— файл, в котором находится функцияmain()
, с экземпляром класса AddressBook
Наследование классов в Qt
В процессе создания программ на Qt, мы часто наследуем встроенные объекты Qt, для того, чтобы добавить в них дополнительный функционал. Это одна из основных концепций программирования классов. Использование наследования для расширения или изменения функционала виджетов имеет следующие преимущества:
- Мы можем создавать реализации виртуальных или чистых виртуальных функций, для осуществления именно того, что нам нужно, и возвращаться к реализации базового класса, когда это необходимо.
- Это позволяет нам инкапсулировать части пользовательского интерфейса внутри класса так, что другим частям приложения не нужно знать об индивидуальных виджетах.
- Подклассы можно использовать для создания кастомных виджетов, а затем использовать этот код в других проектах.
Поскольку в Qt нет конкретного виджета адресной книги, мы унаследуем класс стандартного виджета Qt, и добавим в него новые функции. В этом руководстве мы будем создавать класс AddressBook
, и сможем использовать повторно, когда нам понадобится базовый виджет адресной книги.
Определение класса AddressBook
В файле addressbook.h
будет находиться определение класса AddressBook
.
Мы определим AddressBook
, как подкласс QWidget и создадим конструктор для него. Также, мы будем использовать макрос Q_OBJECT для указания того, что класс использует интернационализацию и механизм сигналов и слотов, даже если все эти возможности не нужны нам на данном этапе.
class AddressBook : public QWidget
{
Q_OBJECT
public:
AddressBook(QWidget *parent = 0);
private:
QLineEdit *nameLine;
QTextEdit *addressText;
};
В этом классе содержится описание свойств nameLine
и addressText
— приватных экземпляров QLineEdit и QTextEdit, о которых упоминалось ранее. Данные, хранимые в nameLine
и addressText
будут использоваться во многих функциях приложения.
Мы не подключаем здесь заголовочный файл <QLabel>
, поскольку не нуждаемся в определении объектов QLabel
на этапе их создания.
Макрос Q_OBJECT реализует некоторые расширенные возможности Qt. В данный момент, он необходим для использования функций tr()
и connect()
.
Мы закончили работу с файлом addressbook
, и переходим к реализации соответствующего ему файла addressbook.cpp
.
Реализация класса AddressBook
Конструктор класса AddressBook позволяет передавать ему параметр QWidget *parent
. Это параметр передается конструктору базового класса. Данный принцип, когда у родительского класса может быть несколько подклассов, используется в Qt для группировки виджетов. К примеру, если вы удалите объект базового класса, все объекты его наследников также будут удалены.
AddressBook::AddressBook(QWidget *parent)
: QWidget(parent)
{
QLabel *nameLabel = new QLabel(tr("Name:"));
nameLine = new QLineEdit;
QLabel *addressLabel = new QLabel(tr("Address:"));
};
addressText = new QTextEdit;
Здесь создаются два экземпляра класса QLabel — nameLabel
и addressLabel
, а также поля ввода nameLine
и addressText
. Функция tr() возвращает локализованную версию строки, если она доступна. В противном случае, функция вернет ту же строку.
Программируя на Qt, полезно знать, как работают слои. В Qt есть три главных класса слоев: QHBoxLayout, QVBoxLayout и QGridLayout. Их используют для позиционирования виджетов.
Мы воспользуемся слоем QGridLayout, для позиционирования надписей и текстовых полей в упорядоченном виде. QGridLayout делит все доступное пространство на сетку, и размещает виджеты внутри клеток с указанными коор динатами. На рисунке выше показано расположение клеток и позиции наших виджетов. Рассмотрим следующий код:
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameLine, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
mainLayout->addWidget(addressText, 1, 1);
Заметьте, что addressLabel
использует параметр Qt::AlignTop для позиционирования. Это сделано для того, чтобы надпись выровнялась по верху клетки с координатами (1, 0). Для более детального понимания работы со слоями, ознакомьтесь с соответствующей документацией.
Для того, чтобы привязать слой к виджету, вызывается функция setLayout():
setLayout(mainLayout);
setWindowTitle(tr("Simple Address Book"));
}
В последней строчке, мы установили заголовок «Simple Address Book» для нашего виджета.
Запуск приложения
Функцию main()
мы поместим в отдельный файл main.cpp
. В main()
мы создадим объект app
класса QApplication. Класс QApplication отвечает за различные ресурсы приложения, такие как шрифт по умолчанию и курсор, а также запускает цикл обработки событий. В любом приложении, написанном на Qt, всегда есть один объект QApplication.
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
AddressBook addressBook;
addressBook.show();
return app.exec();
}
Мы создали виджет AddressBook
в стеке и вызвали функцию show() для его отображения. Тем не менее, виджет не будет показан, пока не запустится цикл обработки событий программы. Мы запускаем цикл обработки событий с помощью вызова функции exec(). Результат, который возвращает эта функция, используется в качестве возвращаемого значения функции main()
. Когда объект AddressBook
будет уничтожен, также удалятся всего его наследники, для предотвращения утечек памяти.
Исходный код всех примеров:
Оригиналы перевода:
Комментарии к статье: 5
Возможность комментировать эту статью отключена автором. Возможно, во всем виновата её провокационная тематика или большое обилие флейма от предыдущих комментаторов.
Если у вас есть вопросы по содержанию статьи, рекомендуем вам обратиться за помощью на наш форум.