К основному контенту

Изучение Qt маленькими порциями. Разбираем ваше первое приложение

Прошлый раз вы установили QtCreator, а затем сгенерировали ваше первое приложение. Всё сработало и у вас теперь есть собственное пустое окно QMainWindow на экране. Всё хорошо, но что же действительно было сделано? Давайте пройдёмся по сгенерированному коду, чтобы стало понятно, что же случилось на самом деле.




Приложение состоит из одного класса и функции main, необходимой для запуска. Давайте посмотрим на эту функцию


main.cpp

#include <QtGui/QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}


В этой функции создаётся экземпляр класса QApplication. Каждому приложению Qt нужен один и только один экземпляр класса QApplication. Он представляет собой само приложение и содержит главный цикл обработки событий.



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


После того как создан QApplication, создаётся MainWindow. Это ваш класс - мы посмотрим его немного позже. После этого показываем MainWindow перед тем, как вызвать метод приложения exec. При вызове exec запускается цикл обработки событий
и начинает свою работу приложение.

Так как же насчёт класса MainWindow? Полное описание класса приведено ниже, но давайте разберём его по частям.


mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QtGui/QMainWindow>

namespace Ui
{
class MainWindowClass;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = 0);
~MainWindow();

private:
Ui::MainWindowClass *ui;
};

#endif // MAINWINDOW_H



Заголовочный файл начинается с включения базового класса QMainWindow и предварительного объявления Ui::MainWindowClass.


Предварительное объявление - это способ указать компилятору C++, что есть класс с заданным именем. Мы можем использовать это имя для определения указателей, но не для работы с самим классом. Перед тем как работать с классом необходимо привести его объявление. Как мы можем определить указатели на класс, который ещё не был определён надлежащим образом? Все указатели имеют одинаковый размер, поэтому компилятор может выделить достаточно памяти независимо от того, куда он указывает. Нам не нужно в нашем заголовочном файле ссылаться на другой заголовочный файл. Это предотвращает открытие ещё одного файла и разбор его при компиляции, тем самым сокращая время сборки.


После включения заголовочных файлов и предварительных объявлений, определяем наш класс MainWindow. Он наследуется от QMainWindow и имеет конструктор, деструктор и указатель типа Ui::MainWindowClass. Нет ничего необычного в этом. Конструктор позволяет передать родительский виджет в наш класс. Стоит обратить внимание, что первая строка объявления содержит макрос Q_OBJECT. Мы зпознакомимся с ним ближе в следующем блогпосте. А пока что просто запомните, что его необходимо там поместить, если вы наследуетесь от QObject напрямую или косвенным образом (QMainWindow inherits QWidget that inherits QObject - вы можете увидеть это на страницах документации для каждого класса в строке, начинающейся с “Inherits…”).


Касательно реализации класса MainWindow. Первые несколько строк содержат включения заголовочных файлов для класса MainWindow и ui_mainwindow.h header file. Последний содержит объявление класса Ui::MainWindowClass. На самом деле он был сгенерирован из файла mainwindow.ui, который мы посмотрим позже. Чтобы у вас перед глазами была полная картина, .ui файл создаётся посредством "рисования" интерфейса пользователя. Это как раз то место, где дизайн приходит в код, так что вы можете с ним что-то сделать.

mainwindow.cpp - part 1

#include "mainwindow.h"
#include "ui_mainwindow.h"


После включения заголовочных файлов идут конструктор и деструктор. Всё, что они делают - просто создают и удаляют ui. В конструкторе также передаются параметры в родительский класс и вызывается ui->setupUi, в которую в качестве параметра передаётся this. Это создаёт разработанный интерфейс пользователя внутри MainWindow.

mainwindow.cpp - part 2

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindowClass)
{
ui->setupUi(this);
}

MainWindow::~MainWindow()
{
delete ui;
}


И, напоследок, я расскажу о рисовании пользовательского интерфейса, создании .ui файла. Сделайте двойной щелчёк по файлу mainwindow.ui в списке файлов QtCreator. Вы увидите что-то похожее на изображённое ниже. Это Designer view из QtCreator, в котором вы можете разрабатывать пользовательский интерфейс.




Созданию интерфейса и добавлению некоторой функциональности мы уделим внимание в следующий раз. До новых встреч!


Комментарии

Популярные сообщения из этого блога

Одно приложение, несколько баз данных

Рецепт от Spring Boot Некоторое время назад мне довелось писать агрегатор информации, разбросанной по нескольким базам данных с разными схемами. Для реализации был выбран Spring Boot. Ну, потому что модный и судя по примерам существенно упрощает жизнь за счет умной автоконфигурации. В этой статье я опишу, что же необходимо сконфигурировать и как, в случае, если вы отошли от стандартного сценария. Первым делом, необходимо прописать настройки доступа к каждой из баз. Например, вот так: Следующим шагом создадим отдельный класс конфигурации (для удобства), в котором определим dataSources: Обратите внимание, как просто получить настройки с помощью @ConfigurationProperties. Правда, пришлось ввести вспомогательный класс BaseDataSourceProperties — наследник DataSourceProperties, в котором область видимости метода getDriverClassName расширена до public. И осталось совсем немного — сконфигурировать JPA-репозитории. Насчет немного я, конечно, пошутил :) В этой части предстоит больше

Может ли TreeSet содержать дубликаты?

Не спешите давать ответ, а лучше запустите код, приведенный ниже. Возможно вы подумаете, что это надуманный пример, но это лишь немного упрощенная версия того кода, с которым мне пришлось столкнуться на практике. Для начала о проблеме, которую был призван решить этот код. В списке объектов надо было оставить объекты с различными именами, причем неважно какой объект из всего набора с таким же именем останется. Сразу же уточню, что на практике в проекте используется Java 7 и класс объектов, добавляемых в TreeSet, не вложен в какой-либо другой, а приведенный здесь вариант использован для краткости. Может возникнуть вопрос почему выбрано именно такое решение. Давайте разберемся, чтобы не повторять ошибку. Первое, что приходит в голову, когда из списка надо удалить дубликаты, - использовать Set. В данной ситуации HashSet не подходит, потому что он использует equals метод для сравнения и отсеивания дубликатов. Но наш программист не сдаётся и вспоминает, что есть же еще TreeSet, в докум

Обработка изображений с ImageMagick

ImageMagick ( http://www.imagemagick.org ) — набор утилит для создания, редактирования, конвертирования и просмотра растровых изображений. Графический режим необходим только для просмотра. Для остальных действий над изображениями достаточно консоли. То есть налицо два отличия от привычных редакторов растровых изображений (вроде GIMP или Krita): использование набора утилит вместо одной программы для операций над изображениями не требуется GUI. Очевидно, что таким инструментом вряд ли будут пользоваться художники, фотографы или дизайнеры. Чтобы разобраться для кого предназначен этот набор, предлагаю ознакомиться с предоставляемыми возможностями. Что умеет ImageMagick? Чтобы ответить на поставленный вопрос я перечислю входящие в набор утилиты, напишу какой функционал предоставляет каждая из них и, конечно же, приведу примеры использования. identify — информационная утилита, воспользовавшись которой можно узнать формат изображения и множество других его свойств (например, высоту,