«Hello, World!» на Qt

    Qt — это кросс-платформенный инструментарий разработки ПО на языке программирования C++. Есть также «привязки» ко многим другим языкам программирования: Python — PyQt, Ruby — QtRuby, Java — Qt Jambi, PHP — PHP-Qt и другие.
    Позволяет запускать написанное с его помощью ПО в большинстве современных операционных систем путём простой компиляции программы для каждой ОС без изменения исходного кода. Включает в себя все основные классы, которые могут потребоваться при разработке прикладного программного обеспечения, начиная от элементов графического интерфейса и заканчивая классами для работы с сетью, базами данных и XML. Qt является полностью объектно-ориентированным, легко расширяемым и поддерживающим технику компонентного программирования.
    В этой статье я покажу как написать простую программу «Hello, World!» с использованием библиотеки Qt4

    Среда разработки


    Сначала определимся со средой разработки. Лично я для написания программа использую кросс платформенную IDE Code::Blocks (подробнее про работу в этой IDE с Qt4 можно почитать тут). Так же есть плагины для работы с Qt в Eclipse. Коммерческая версия Qt под MS Windows может быть интегрирована в MSVS. Программы так же можно писать в любом текстовом редакторе, а потом компилировать их из командной строки.
    Для наглядности, я покажу как компилировать программы, написанные на Qt, вручную.

    Первая программа


    Сначала в любом текстовом редакторе создадим файл и назовем его, например, main.cpp
    Напишем в нем следующее:
    1. #include <QtCore>
    2. #include <QtGui>
    3.  
    4. int main(int argc, char* argv[]) {
    5.     QApplication app(argc, argv);
    6.     QDialog *dialog = new QDialog;
    7.     QLabel *label = new QLabel(dialog);
    8.     label->setText("<font color=red>Hello, World!</font>");
    9.     dialog->show();
    10.     return app.exec();
    11. }
    * This source code was highlighted with Source Code Highlighter.

    В строках 1 и 2 мы подключили заголовочные файлы Qt в которых находятся основные классы.
    В строке 4 мы объявили функцию main — главную функцию, с которой начинается выполнение любой программы. Она возвращает целое число (результат работы программы; 0 — если все в порядке) и принимает на вход две переменные — число параметров командной строки и массив, в котором они сохранены.
    В строке 5 мы создаем объект приложения. Этому объекту мы передаем переменные командной строки.
    В строке 6 мы создаем диалог — графическое окно прямоугольной формы, с заголовком и кнопками в верхнем правом углу. Создаем метку (строка 7). При создании метки мы передаем ее конструктору указатель на диалог, который становится ее родителем. При удалении родителя автоматически удаляются все его потомки, что очень удобно. Затем устанавливаем надпись метки путем вызова функции setText() (строка 8). Как видно из примера, для отображаемого текста можно использовать html-теги.
    В строке 9 мы отображаем наше диалоговое окно с меткой на экране.
    И, наконец в строке 10 мы запускаем цикл обработки событий операционной системы приложением. Результат работы объекта мы возвращаем как результат работы программы.

    Компиляция


    Теперь скомпилируем написанную программу.
    Перейдем в каталог, куда мы сохранили наш файл main.cpp и выполним команду

    $ qmake -project

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

    TEMPLATE = app
    TARGET =
    DEPENDPATH += .
    INCLUDEPATH += .

    # Input
    SOURCES += main.cpp


    Как видим файл с исходными текстами добавился автоматически. Выполним команду

    $ qmake

    В результате мы получим Makefile, который используем для того что бы скомпилировать программу, выполнив следующую команду:

    $ make

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


    Вторая программа


    Что бы получить полный контроль над создаваемыми окнами и другими виджетами, необходимо создавать производные от них классы. Создадим производный класс MyDialog. В качестве родительского будем использовать класс QDialog. Описание нашего класса поместим в заголовочный файл mydialog.h:
    1. #include <QDialog>
    2. #include <QPushButton>
    3. #include <QLabel>
    4. #include <QVBoxLayout>
    5.  
    6. class MyDialog : public QDialog {
    7.     Q_OBJECT
    8. public:
    9.     MyDialog(QWidget *parent = 0);
    10. };
    * This source code was highlighted with Source Code Highlighter.
    В первых четырех строках мы подключаем необходимые заголовочные файлы используемых графических элементов — диалога, кнопки, надписи и вертикального менеджера компоновки. Использовать такие крупные заголовочные файлы как <QtGui>, <QtCore> и др. в больших проектах не рекомендуется, так как это увеличивает время компиляции.
    В шестой строке мы определили наш класс производным от QDialog.
    На следующей строчке мы указали макрос Q_OBJECT, который указывает предпроцессору Qt что данный класс будет использовать дополнительные возможности Qt, например, систему сигналов и слотов.
    На строке 9 мы указываем конструктор нашего диалогового окна. У него только один входной параметр — указатель на родительский объект (0 если родителя нет).
    Конструктор нашего класса мы определим в файле mydialog.cpp:
    1. #include "mydialog.h"
    2.  
    3. MyDialog::MyDialog(QWidget *parent) : QDialog(parent) {
    4.     QVBoxLayout *layout = new QVBoxLayout(this);
    5.     QLabel *label = new QLabel(this);
    6.     label->setText("<font color=red>Hello, World!</font>");
    7.     QPushButton *button = new QPushButton(this);
    8.     button->setText("Close");
    9.     layout->addWidget(label);
    10.     layout->addWidget(button);
    11.     connect(button, SIGNAL(clicked()), this, SLOT(close()));
    12. }
    * This source code was highlighted with Source Code Highlighter.

    В строке 4 мы создаем менеджер компоновки, который будет автоматически отображать все добавленные в него виджеты вертикально. Создание надписи аналогично предыдущему примеру.
    В строках 7 и 8 создаем кнопку и устанавливаем ее текст. На следующих двух строчках мы добавляем наши виджеты в менеджер компоновки что бы он их автоматически упорядочил.
    В строке 11 мы подключаем сигнал нажатия clicked() кнопки button к слоту close() нашего диалогового окна. У каждого объекта Qt могут быть свои сигналы и слоты, которые можно подключать к сигналам и слотам других объектов и таким образом осуществлять коммуникацию между элементами программы.
    Файл main.cpp примет следующий вид:
    1. #include <QApplication>
    2. #include "mydialog.h"
    3.  
    4. int main(int argc, char* argv[]) {
    5.     QApplication app(argc, argv);
    6.     MyDialog *dialog = new MyDialog;
    7.     dialog->show();
    8.     return app.exec();
    9. }
    * This source code was highlighted with Source Code Highlighter.

    Пересоздаем проект командой

    $ qmake -project

    что бы новые файлы автоматически в него добавились и компилируем его. Вот так выглядит наша новая программа:


    Третья программа


    Если диалоговое окно содержит много графических элементов, то создавать такие окна довольно утомительно. Для упрощения этого процесса есть инструмент под названием Qt Designer. Запускаем его

    $ designer

    и выбираем создание диалогового окна без кнопок. Добавляем на него метку и кнопку, редактируем их текст. С помощью инструмента редактора сигналов и слотов (Signal/Slot Editor) подключаем сигнал нажатия clicked() кнопки button к слоту close() диалогового окна. Располагаем их вертикально с помощью менеджера компоновки. Сохраняем полученный файл под именем mydialog.ui. Позже он будет автоматически преобразован в заголовочный файл с именем ui_mydialog.h.
    Изменяем заголовочный файл нашего диалогового окна mydialog.h следующим образом:
    1. #include "ui_mydialog.h"
    2.  
    3. class MyDialog : public QDialog, public Ui::Dialog {
    4.     Q_OBJECT
    5. public:
    6.     MyDialog(QWidget *parent = 0);
    7. };
    * This source code was highlighted with Source Code Highlighter.

    Все заголовочные файлы в нем заменяются на «ui_mydialog.h», а наследование становится множественным.
    Конструктор значительно упрощается:
    1. #include "mydialog.h"
    2.  
    3. MyDialog::MyDialog(QWidget *parent) : QDialog(parent) {
    4.     setupUi(this);
    5. }
    * This source code was highlighted with Source Code Highlighter.

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

    Заключение


    В этой статье было показаны базовые принципы программирования на С++ с использованием Qt4. Если хабрасообществу понравится данная публикация, то я продолжу цикл публикаций об использовании Qt4.
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 72

      +2
      Было бы неплохо если скрины бы добавили для наглядности. Есть, конечно, специ, которые взглянув на код сразу представляют картину, но я, простите, обычный смертный. Если не трудно, приложите скрины.
        +2
        Хорошо, сейчас сделаю.
        +2
        Когда будет достаточно кармы перенесите в блог Qt Software

        Сам использую Qt понемногу… выбирал гуи когда, выбрал кьюте из-за кросплатформености… но жаль минус один есть сильный, в винде что бы работала хоть та же программа Хеллоу ворлд надо в комплекте давать ещё и библиотеку размером в метров 7… прога весит пару кб, а библиотека дофига… пожалуй это единственный минус…
        В линуксе проще, там почти у всех кьюте уже установлен ^_^
          0
          добавил кармы ;)
            0
            Кстати, если собрать Qt как static и проект слинковать статически, разве это не поможет? Каким будет размер бинарника?
              0
              Немного меньше… люди много эсперементировали с этим, пару метров максимум уменьшали, убирая всё что можно убрать, через статик и т.п., но всёравно многовато получется…
                +5
                Учитывая что современные программы тащат с собой .Net, MS XML Parser 6.0, VC 2005 redistrable и т.д., то пара библиотек на 14 мегабайт (QtCore.dll и QtGui.dll) никого не пугают.
                  –4
                  Разница не в размере самой программы, а в том, сколько пользователю качать.
                  Первые (.Net, MS XML Parser 6.0, VC 2005 redistrable ...) наверняка уже установлены в системе. А Qt или Gtk придется ставить.
                    0
                    Ява машину тоже например необходимо ставить в систему…

                    А все dll из состава Qt можно просто скопировать один раз в system32 и забыть про них.
                    • НЛО прилетело и опубликовало эту надпись здесь
                        0
                        На Яву можно рассчитывать, а вот рассчитывать на то, что пользователь будет копировать dll себе в system32 или у него стоит прога на Qt, которая их уже скопировала туда, сложно.
                        • НЛО прилетело и опубликовало эту надпись здесь
                            0
                            Да можно, просто все-равно их тащить придется в инсталлере. Только если проверять и если нет, то загружать
                            • НЛО прилетело и опубликовало эту надпись здесь
                                0
                                net и jre сейчас ставят чуть ли не по дефолту вместе с виндой, в крайнем случае пишут в системных требованиях, об установке gtk и qt должен позаботиться разработчик
                                  0
                                  дык разработчик об этом и заботиться созданием инсталлера
                                    0
                                    Дык речь изначально шла о том, что размер инсталлера получается слишком большой для «Hello World» по сравнению с теми же net и java. Да и нет, насколько я знаю, хотя бы что-то вроде qt или gtk redistrable для винды, чтоб можно было указать в требованиях, как и нет репозиториев и менеджеров пакетов к ним, которые могли бы все зависимости вытянуть.
                                      0
                                      Я мало знаком с Qt, но вроде бы есть отдельные инсталляторы библиотеки. Так что не обязательно в каждый инсталлятор утилит типа «helloworld» вставлять всю Qt. Тем более, если у пользователя уже стоит Qt более новой версии, и с большой вероятностью она совместима.
                        +2
                        Пользователи сейчас качают из сети сериалы и гигабайтные образы игр, так что несколько мегабайт, я считаю, ничего не значат.
                      0
                      Если все правильно слинковать, то размер слинкованных от Qt библиотек будет прямо пропорционалей количеству используемых классов. А в небольшой програмке их не может быть много.
                      0
                      статично собраный релизный бинарник будет весить 4.5+ Мб, если сжать upx-ом, то 2+ Мб
                      0
                      Важнее не размер исходных файлов, а то как хорошо их можно сжать в тот же архив или установщик. А данные библиотеки все очень хорошо поддаются сжатию, раза в 1.5 — 2 точно.
                      +3
                      давайте смотреть на вещи реально, ок? как много серьезного софта — это «проги на пару кб»?
                      я думаю таких нет в принципе. а чем сложнее (не в плане понимания, а плане архитектуры, количества кода и т.д.) проект, тем меньше болит голова у разработчиков о том, сколько же линкованного кода с собой потащит их продукт.
                      и я думаю семь метров в виде «хвостика» к 300-м мало кого заставят страдать :)
                      особенно с учетом всех тех приемуществ, которые получашь используя кьют.

                        0
                        Вы так говорите, как будто все ваши программы весят пару килобайт. Если это не очередной сиди-эджектор, то размер QT по сравнению с размером программы не так уж и сильно выделяется.
                          0
                          В линуксе не факт, что Qt установлен, но есть менеджер пакетов, поэтому, о том, что Qt может не оказаться можно просто забыть. Под Windows ИМХО лучшее решение — сделать инсталятор Qt и писать на оф. сайте программы «Если при запуске программы появляеся <такое-то> сообщение об ошибке, то Вам нужно скачать и применить ещё и вот этот инсталлятор.»
                        • НЛО прилетело и опубликовало эту надпись здесь
                            0
                            >Использовать такие крупные заголовочные файлы как, и др.
                            и далее… что-то, по-моему, съехало, видимо из-за <, а не < в имени файла

                            А так продолжайте, конечно, очень интересная тема

                              0
                              < имелось в виду

                              как-то странно хабр с сущностями обращается, в два прохода :)
                                0
                                черт и предпросмотр не помог… в общем & lt; (без пробела)
                                  0
                                  Спасибо, сейчас поправлю
                              +1
                              Спасибо всем за добрые отзывы
                                +3
                                Немного критики, если позволите. Статья, как я понял, ориентирована на новичков. В этом случае у меня, будь я новичком, сложилось бы достаточно сумбурное представление.
                                «При удалении родителя автоматически удаляются все его потомки, что очень удобно» — с какой стати? В с++ такого не предусмотрено. Здесь, если Вы затронули такое поведение, вероятно, надо хотя бы кратко рассказать про класс QObject.
                                «На следующей строчке мы указали макрос Q_OBJECT, который указывает предпроцессору Qt что данный класс будет использовать дополнительные возможности Qt, например, систему сигналов и слотов.» — каких сигналов? каких слотов? Что это такое вообще? Далее идет краткое объяснение: «У каждого объекта Qt могут быть свои сигналы и слоты,...» опять же, что значит «каждый объект Qt»? Любой класс? Тогда это неверно. Вероятно QObject? Тогда следует все же провести краткий экскурс в этот класс.
                                  0
                                  Я согласен с данным замечанием, но если бы в данной статье я начал бы подробнее рассказывать по сигналы и слоты, она получилась бы раза в два больше. Поэтому я решил показать простой пример, а более подробно разобрать класс QObject и производные от него в следующей статье
                                    0
                                    Может быть тогда стоило изначально проектировать статью с таким учетом? То есть не упоминать о тех вещах, которые не могут быть сейчас раскрыты хотя бы для частичного понимания.
                                      0
                                      Я хотел в первой статье показать практический пример, который можно взять, скомпилировать и посмотреть что получится. А более углубленные разъяснения оставить на потом. Может быть такой подход и не совсем правильный…
                                        +1
                                        Это наверное зависит от читателя. Кто-то не знает с чего начать, и скопировать-вставить-скомпилировать — это для него выход. Кто-то не может сдвинуться с места, не поняв как оно в итоге работает.
                                  +3
                                  про IDE, можно было бы упомянуть еще QT Creator…
                                    0
                                    QT Creator все еще находится в состоянии беты. Когда я пытался его использовать, то столкнулся с проблемой что он использует системную локаль для отображения исходных кодов. Учитывая что я пишу на разных компьютерах с разными операционными системами и локалями, это затруднило его применение.
                                    Хотя это, конечно, мой недочет что я его забыл :)
                                    • НЛО прилетело и опубликовало эту надпись здесь
                                        0
                                        Qt Creator наше ффсе… правда только если его регулярно обновлять из снепшотов
                                      +1
                                      Вы во всех трех программах не удаляете dialog, что нехорошо.
                                        0
                                        Он удаляется автоматически при завершении программы. Дополнительных действий со стороны программиста в данном случае не требуется.
                                          0
                                          Кстати да, я почему-то не обратил внимание. Действительно диалог нужно удалять в данном случае. Если бы Вы его создали статически, то он бы удалялся при завершении функции main. А так удаляется только указатель.
                                          «Он удаляется автоматически при завершении программы» — поясните, пожалуйста, ведь у диалога же нет парента в данном случае.
                                        • НЛО прилетело и опубликовало эту надпись здесь
                                            0
                                            Во-первых можно подключить сигнал закрытия последнего окна к слоту deleteLater диалога.
                                            Во-вторых можно создать диалог статически.
                                              0
                                              можно перед ретерном, но после app.exec, обычно туда ставят «правильное» удаление объектов перед завершением приложения
                                              • НЛО прилетело и опубликовало эту надпись здесь
                                                  0
                                                  Так то оно так, но нужно говорить об этом в статье. Особенно в статье, которая претендует на аудиторию из новичков. Иначе данное поведение будет списано на «фичу Qt» (особенно в свете фразы «При удалении родителя автоматически удаляются все его потомки, что очень удобно») и будет делаться повсеместно.
                                                    0
                                                    Когда думал как уменьшить число строчек кода в примере случайно удалил из него эту:

                                                    dialog->setAttribute(Qt::WA_DeleteOnClose);

                                                    Если установить это атрибут для главного окна, то оно автоматически будет удалятся при закрытии.
                                                      0
                                                      Для уменьшения числа строчек можно было сделать так:
                                                      QApplication a(argc, argv);
                                                      QLabel l("Hello, World!");
                                                      l.show();
                                                      return a.exec(); :)
                                                        0
                                                        В то же время я не хотел отказываться от создания диалогового окна что бы повысить наглядность примера :)
                                                          0
                                                          Ну такую реализацию тоже можно было упомянуть. Ибо, вспоминая себя, как начинающего пользователя Qt — до некоторого момента я свято верил, что такие вещи как QLabel, QPushButton и прочие мелкие виджеты не могут быть никак показаны кроме как на диалоге или другом более общем виджете (QMainWindow например) :)
                                                          • НЛО прилетело и опубликовало эту надпись здесь
                                                          • НЛО прилетело и опубликовало эту надпись здесь
                                                      • НЛО прилетело и опубликовало эту надпись здесь
                                                    +1
                                                    Ну и в-третьих написать что-то вроде:
                                                    int ret = a.exec();
                                                    delete dialog;
                                                    return ret; :)
                                                    • НЛО прилетело и опубликовало эту надпись здесь
                                                  0
                                                  ну вот, меня опередили (я тоже собирался начинать цикл статей по C++/Qt);) ну тогда если что помогу…
                                                    +1
                                                    Рыночную экономику ещё не отменили, что плохого в конкуренции?)
                                                      0
                                                      а смысл писать одно и тоже двум разным людям?;)
                                                        0
                                                        Как вариант можете написать статьи об использовании Qt для embedded systems или для Windows Mobile.
                                                          0
                                                          хехе, чтобы такое писать это знать надо;) посмотрим, что будет дальше, может какую-нить ветку напишу
                                                    0
                                                    А почему автор забыл упомянуть об официальной IDE от Нокии — QtCreator? Для Qt это лучший выбор на сегодня, я так думаю.
                                                    www.qtsoftware.com/developer/qt-creator
                                                      0
                                                      В комментариях выше этот вопрос уже обсуждался. Она еще находится на стадии бета тестирования. Но я с нетерпением жду когда будет релиз
                                                      0
                                                      Пожалуйста, пишите еще =)
                                                        0
                                                        Непременно :)
                                                        0
                                                        Отлично, спасибо! :) а если у меня есть баш-скрипт, который вызывает ffmpeg с определёнными параметрами и конвертирует видео, мжно ли к нему прикрутить такой GUI со статусбаром? Извиняюсь заранее если вопрос глупый
                                                          0
                                                          Можно. Для этого есть класс QProcess
                                                            0
                                                            Для прикручивания GUI к скриптам уже давно и успешно применяется Tcl/Tk. Не тратьте время на Qt (в данном случае). Не подходит он для написания морд к скриптам.

                                                            Вызов скрипта:

                                                            set scriptOutput [exec myScript.sh]
                                                            0
                                                            Достали хелловорлды

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

                                                            Самое читаемое