Пишем адресную книгу на Qt — часть 1

5 комментариев

Это руководство является введением в программирование графических интерфейсов на Qt.

Адресная книга, написанная на Qt

Здесь мы изучим несколько базовых компонентов, включая:

  • Виджеты и менеджеры слоев
  • Классы-контейнеры
  • Сигналы и слоты
  • Устройства ввода и вывода

Если вы только что начали изучать Qt, мы рекомендуем прочитать введение в программирование на Qt.

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

Разработка пользовательского интерфейса

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

Базовый интерфейс адресной книги на Qt

Нам необходимы два объекта QLabelnameLabel и addressLabel, а также два текстовых поля: nameLine — объект класса QLineEdit и addressText — объект QTextEdit. Текстовые поля нужны для того, чтобы пользователь мог вводить имена и адреса своих контактов. Позиции используемых виджетов отмечены на рисунке ниже.

Виджеты приложения AddressBook

Для реализации адресной книги используются три файла:

  • addressbook.h — определение класса AddressBook
  • addressbook.cpp — реализация класса AddressBook
  • main.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;

Здесь создаются два экземпляра класса QLabelnameLabel и addressLabel, а также поля ввода nameLine и addressText. Функция tr() возвращает локализованную версию строки, если она доступна. В противном случае, функция вернет ту же строку.

Программируя на Qt, полезно знать, как работают слои. В Qt есть три главных класса слоев: QHBoxLayout, QVBoxLayout и QGridLayout. Их используют для позиционирования виджетов.

Позиционирование виджетов в 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

Подождите, загружаются комментарии...

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

Если у вас есть вопросы по содержанию статьи, рекомендуем вам обратиться за помощью на наш форум.