Введение в Qt Quick 2 и QML

Решил тут ради интереса немного почитать про такую библиотеку, как Qt. Заинтересовала она меня именно в плане создания GUI, так как в C++ с этим достаточно туго, а Qt - одна из немногих кроссплатформенных библиотек, позволяющая удобно делать современные гибкие графические интерфейсы к программам. Раньше с ней совершенно никакого опыта работы я не имел, поэтому пару недель занимался неспешным чтением документации.

В какой-то из версий Qt (если не ошибаюсь, в 4.7) появилась возможность делать интерфейсы на декларативном языке QML 1.0 (и модуль QtDeclarative, определяющий всякие штуки для рисования интерфейсов), а в 5-й версии Qt появился QML 2.0 и QtQuick 2.0 (бывший QtDeclarative). Их я и стал изучать. В этой статье я расскажу об этих модулях в меру своих знаний, покажу пару несложных примеров их использования, а кто дочитает до конца статьи, получит еще один бонусный пример, который я написал, пока изучал библиотеку. :)

Для того, чтобы понять идеологию и принципы работы интерфейса, написанного на QML, нужно почитать документацию, но я поясню упрощенно: вы пишете объявления различных объектов (таких, как прямоугольники, кнопки, окна и т.д.), описываете, как они должны быть расположены (координаты фиксировать не нужно, очень легко построить "резиновый" (т.е. автоматически подстраивающийся при изменении размеров окна) интерфейс, как в WPF), а Qt за вас всё отрисовывает и контролирует. QML тесно интегрирован с JavaScript, в результате очень удобно писать обработчики различных событий, привязки и просто вспомогательные функции. Их можно делать как прямо внутри QML-файлов, так и выносить в отдельные JS-файлы. В целом, QML и Qt Quick мне понравились гораздо больше, чем XAML и WPF. Во-первых, QML кажется мне проще, нагляднее и легче читается, чем XAML, во-вторых, позволяет писать кроссплатформенные интерфейсы под множество платформ (например, я смог скомпилировать небольшое приложение под Windows Phone 8.1 и запустить у себя на телефоне, при этом оно работало и на обычной Windows 7), в-третьих, очень тесно связан с JavaScript, что позволяет сделать полноценное приложение, вообще не написав ни строчки кода на C++. Есть, конечно, и минусы. С моей точки зрения, это необходимость таскать со своим приложением DLL-файлы от Qt, которые занимают немало места. С другой стороны, это оправдано, ведь библиотека кроссплатформенная. Можно, конечно, собрать всё статически, но тогда вы нарушите лицензию LGPL, да и приложение все равно будет занимать прилично места. В C# библиотека .NET просто устанавливается в Windows, но у пользователя изначально тоже может отсутствовать нужная версия. В Qt же есть специальная утилита, позволяющая собрать все необходимые для написанного приложения библиотеки в один каталог, чтобы потом заархивировать всё необходимое в инсталлятор (о ней я расскажу в конце статьи). Увы, есть в Qt и баги, на которые я наткнулся (пришлось выписать их в багтрекер), но их, к счастью, исправляют за разумное время. Также, возможно, QML имеет несколько более скудные возможности по сравнению с WPF, но я этого пока не заметил. Да и кастомные компоненты в QML делать чрезвычайно просто. Вынося вердикт, скажу, что плюсы библиотеки сильно перевешивают ее минусы, и в будущем я планирую продолжить ее изучение и использование.

А пока что, чтобы не быть голословным, приведу простой пример, как с этим вообще работать (скриншоты будут с Windows, но то же самое совсем не сложно будет проделать и на другой ОС, например, Ubuntu или Mac OS).

1. Для начала нужно скачать онлайн-инсталлятор Qt последней версии. Можно скачать и оффлайн-инсталлятор на выбор. Для Windows доступны сборки с OpenGL и с ANGLE (это переходник с DirectX под интерфейс OpenGL). Разработчики Qt утверждают, что ANGLE под Windows сейчас работает стабильнее (по крайней мере, в версии 5.4.1, для которой я всё и описываю), особенно на старых системах, поэтому можно установить сборку с его использованием.

2. Теперь инсталлируем Qt. У вас уже должна быть установлена какая-нибудь Visual Studio. У меня есть 2013, поэтому для нее я сборку и скачивал.

3. Запускаем Qt Creator, в нем и будем вести разработку. Можно, конечно, разрабатывать и в Visual Studio, установив для этого специальный аддон Qt для Visual Studio, но в этом случае у вас не будет кроссплатформенных файлов проектов, которые можно открыть в программе Qt Creator на другой ОС, кроме того, будет меньше удобств при работе непосредственно с Qt и QML.

В Qt огромное количество различных примеров, по которым можно учиться. Например, можно просмотреть все примеры по теме Qt Quick. Для этого нужно выбрать секцию "Examples" в Qt Creator и в строку поиска ввести "quick":

Но мы сейчас создадим простейшее приложение с использованием Qt Quick на языке QML с нуля. Для этого выбираем секцию "Projects" и нажимаем "New project". Выбираем тип проекта "Application", "Qt Quick Application":

Этот тип приложения подразумевает программу на C++ с использованием QML. Необходимый код на C++ за нас сгенерируется автоматически, поэтому можно будет написать приложение на чистом QML и JavaScript. Нажимаем "Choose", вводим имя проекта (я задал mytest) и указываем, в какой директории его создавать, нажимаем "Next". Далее будет предложено выбрать набор компонентов, с использованием которых мы будем делать наш интерфейс. Здесь можно выбрать Qt Quick последней версии (2.4), этот выбор в любом случае никак не будет вас ограничивать и нужен только для того, чтобы Qt Creator смог сгенерировать набор импортов в файлах интерфейса, которые он создаст, и сами файлы по умолчанию. Итак, нажимаем "Next". Теперь выбираем настройки сборки (версия библиотеки Qt и Visual Studio). Если вы скачивали только одну версию Qt для какой-то конкретной версии Visual Studio, то у вас будет доступен единственный выбор:

Нажимаем "Next", затем "Finish", и Qt Creator генерирует тестовый проект для нас. Этот проект будет содержать один простой файл с кодом на C++ и пару файлов на QML:

Можно собрать и запустить проект, нажав Ctrl+R. Это обычный "Hello, World":

Перейдем к написанию собственного кода. Сделаем, например, нашу собственную кастомную кнопку и расположим несколько таких кнопок с текстом определенным образом в окне приложения. Сейчас проект содержит файл main.qml (он запускается из C++) и MainForm.ui.qml. Файлы *.ui.qml появились в Qt недавно, по идеологии Qt их рекомендуется редактировать в графическом дизайнере интерфейсов (QML Puppet), который вы можете открыть, дважды кликнув на названии файла:

Более того, в файлах *.ui.qml нельзя использовать JavaScript, исключительно QML. Мне не очень понравилась эта идеология, и, как мне кажется, гораздо удобнее писать интерфейсы вручную без дизайнера (по крайней мере, несложные). Дизайнер интерфейсов может быть полезен только для дизайнеров интерфейсов :D. Поэтому я удаляю этот файл из проекта, нажимая Del и ставя флажок "Delete this file permanently". После этого нужно правой кнопкой мыши кликнуть на названии проекта (mytest в моем случае) и выбрать "Run qmake", иначе проект не соберется. Это нужно иногда делать при добавлении новых файлов в проект или удалении файлов из проекта. (Кстати, если в окне выбора версии Qt Quick при создании проекта выбрать 2.3 или более раннюю, то файл *.ui.qml создаваться не будет). Теперь откроем файл main.qml и напишем туда следующий код:

Этот код содержит пару импортов (непосредственно QtQuick и QtQuick.Window для создания элемента Window). Нажмем Ctrl+R или кнопку "Run" и увидим пустое окно с белым фоном. Что ж, основное окно подготовили, теперь можно приступать к созданию кастомной кнопки. Забегая вперед, скажу, что в Qt Quick есть библиотека Controls, которая уже содержит набор готовых контролов (таких как кнопки, поля ввода и т.д.), поддерживающих кастомные стили и стили по умолчанию для разных ОС. Но я покажу, как сделать свой собственный, чтобы вы могли оценить простоту создания новых компонентов. Итак, кликаем правой кнопкой мышки на файле ресурсов qml.qrc, выбираем "Add New...", далее выбираем Qt -> QML File (Qt Quick 2):

Нажимаем "Choose...", вводим имя файла (например, MyButton), нажимаем "Next". Имя нашего компонента будет совпадать с именем файла (при этом, если первая буква имени файла строчная, например, myControl, то компонент будет всё равно называться с заглавной - MyControl). Далее можно указать, в какой каталог в ресурсах положить этот файл, но здесь ничего менять не будем, нажимаем "Finish". После этого в наш проект добавится файл MyButton.qml и сразу откроется. Мы увидим следующий код:

Здесь, как видно, просто объявляется прямоугольник с заданной шириной и высотой. Версию QtQuick в директиве import можно изменить на более новую (2.3). Давайте теперь сделаем нашу кнопку желтой по умолчанию, со скругленными углами и рамкой, а также уберем фиксированную ширину и высоту, так как они пока что будут задаваться из кода, который будет эту самую кнопку создавать:

Эта кнопка пока не обрабатывает события клика и не умеет отображать текст. Но сейчас мы поместим ее на основную форму, чтобы удобнее было совершенствовать её дальше и отлаживаться. Для этого отредактируем файл main.qml, который до сих пор содержал только пустое окно:

Этот код должен быть достаточно понятен. Если вы решите поподробнее прочитать про какие-то элементы (например, ColumnLayout, anchors или прикрепленное свойство Layout, то их описание с примерами использования очень легко находится в гугле). После компиляции и запуска мы увидим приложение с тремя кнопками разного цвета:

Наши кнопки пока что не поддерживают отображение текста и не отслеживают события кликов (хотя уже автоматически подстраиваются под размер окна). Нужно это исправить. Начнем с текста. Вернемся к файлу MyButton.qml:

Здесь мы добавили свойство text, пробросив его в дочерний элемент Text, а также значение ширины и высоты кнопки по умолчанию. Эти значения будут использоваться, если кнопка не вписана в лейаут (который сам задает размер элемента). Проверим, что у нас получилось, добавив текст к кнопкам в main.qml:

Скомпилировав и запустив приложение, увидим следующее окно:

Уже лучше! Теперь оживим кнопки, чтобы они реагировали на клик мышкой. Вернемся к файлу MyButton.qml. Сразу после свойства text добавим сигнал:

А для обработки клика мышью существует специальный элемент MouseArea. Добавим его в конец кода нашей кнопки:

Как видно, этот элемент (он невидимый) будет заполнять всю кнопку. При клике на нем мы будем вызывать наш сигнал clicked. Что ж, теперь осталось навесить какой-нибудь обработчик этого сигнала. Сделаем, чтобы при нажатии на кнопку "Hello, world!" открывалось соответствующее окно, а при нажатии на "Quit" приложение закрывалось. Открываем main.qml и редактируем код. Для начала добавим импорт в начало кода:

Это необходимо, чтобы создать диалоговое окно. Теперь добавляем само окно в конец кода Window:

Теперь навесим обработчик на наш сигнал "clicked":

Чтобы добавить обработчик сигнала, следует написать "on" + название сигнала ("clicked") с заглавной буквы. Теперь добавим такой же обработчик для последней кнопки:

Компилируем, запускаем и видим, что всё отлично работает:

Итак, в несколько простых шагов мы написали приложение с собственными кнопками! Конечно, можно их совершенствовать и дальше: добавить навигацию по нажатию TAB и Space/Enter, какую-нибудь анимацию при наведении курсора, комбинации клавиш быстрого доступа, и всё это делается тоже достаточно просто. Однако, с этим я предлагаю вам разобраться самим, а основные принципы работы с Qt Quick и QML я изложил.

Осталось только собрать приложение, чтобы можно было его кому-нибудь передать. Для этого сначала выберем конфигурацию сборки "Release" в Qt Creator:

Затем соберем приложение (Ctrl+B). Теперь откроем каталог, в который Qt Creator собрал программу. У меня это каталог на уровень выше mytest: ../build-mytest-Desktop_Qt_5_4_1_MSVC2013_32bit-Release/release. Здесь мы увидим mytest.exe, но если попробуем запустить, то увидим ошибку (не хватает библиотек). К счастью, под Windows в Qt есть специальная утилита, которая поможет нам с этим. Она называется windeployqt.exe и входит в состав библиотеки Qt. Добавим путь к ней в переменную окружения PATH (если вы еще этого не сделали). У меня она находится в каталоге C:\Qt\Qt5.4.1_angle\5.4\msvc2013\bin, но у вас, вероятно, будет лежать в другом. Далее открываем консоль (cmd), переходим в каталог с файлом mytest.exe и выполняем следующую команду:

После этого в директории с файлом mytest.exe появятся все необходимые библиотеки Qt, от которых зависит программа, включая файлы, относящися к QML. Кроме того, здесь же окажется и файл vcredist_x86.exe - он необходим тем, у кого не установлены C++ Runtime от VC2013. Смотрим, сколько же весит всё это добро... 73 мегабайта! Да, в этом есть определенное неудобство, но с этим ничего не поделаешь. Есть, конечно, подозрение, что windeployqt перестраховывается и кидает больше файлов, чем необходимо приложению для работы, но проверять это у меня особого желания не было. Еще можно собрать Qt с меньшим количеством опций, получив таким образом более компактный набор библиотек. При желании вы сможете это сделать самостоятельно.

Итак, если вы дочитали до этого места статьи, то я вас точно заинтересовал! Поэтому я выкладываю небольшой бонус - это тетрис, написанный мной полностью на QML и JavaScript в процессе изучения Qt Quick. Он определенно имеет не самые качественные исходники, но для ознакомления с некоторыми воможностями Qt Quick вполне подойдет.

Скачать код проекта с кнопками и его собранный вариант
Скачать код тетриса и его собранный вариант

Введение в Qt Quick 2 и QML: 18 комментариев

  1. >> У вас уже должна быть установлена какая-нибудь Visual Studio
    Можно ведь вариант с MinGW поставить, у кого студии нет, всё равно разработка в QtCreator.

    1. Да, можно и так, спасибо. Я, честно говоря, не смотрел, какой список компиляторов поддерживается Qt Creator'ом, так как у меня уже была студия.

  2. Спасибо за статью. Осталось следующую про qss написать))
    Ранее в Qt было очень много различных багов. Сейчас с появлением 5-й ветки их стало просто много, без приставки "очень". Плата за оупенсорс.
    Касательно размера на выходе - да, начиная с 5-й версии Qt тянет все, что можно и нельзя, причем библиотеки стали занимать значительно больше, по сравнению со своими аналогами из 4-й версии. Помню под винду мы компилили проект компилятором из Вижул студии 13-й, не помню правда название, тогда сборка занимала раза в 2 меньше.

    1. Сейчас баги, как я понял, они стараются исправлять, так как те же исходники Qt теперь еще и продаются по нескольким коммерческим лицензиям, а продавать забагованную библиотеку как-то не очень с их стороны было бы.

  3. Всегда хотел изучить qt , но руки не доходили . И видимо не дойдут пока что :(
    Некоторые вопросы появились от статьи .
    Qml это сейчас стандарт оконного интерфейса для qt ? Или все таки дополнительная фича ? Если дополнительная , можно пример тех же окошек на qt без но qml ? Любопытно какой выигрыш будет по размеру , производительности , скорости разработки ?

    Может добавить в статью методику сопряжения qml с собственно плюсами ? То есть что я должен делать , чтобы привязать обычный плюсовый callback к кнопке в qml ? Нужно где-то его объявлять , приводить к какому-то типу ? Неясно .

    Ну и ссылок на литературу еще бы добавить. А то типа чел прочел , заинтересовался , куда ему дальше читать ?

    1. 1. По вопросу интерфейса без QML - есть виджеты, но я с ними не пробовал работать, руки не дошли. QML изначально позиционировался как средство создания интерфейсов для мобильных платформ, но теперь вроде как любые интерфейсы на нем удобно делать, так как добавили QtQuick Controls и прочие фичи.

      2. Сопряжение с C++ не описал в статье, потому что она и так достаточно объемная получилась. Вероятно, напишу что-то еще чуть позже на эту тему.

      3. По поводу литературы - я читал документацию на сайте Qt (http://doc.qt.io/qt-5/). Она там очень подробная, а в Qt Creator вдогонку есть масса примеров, которые также описываются и на сайте. Ссылки на соответствующие разделы и статьи в документации я дал. По книгам сказать ничего не могу, так как не читал.

  4. Еще пару комментариев .
    Решил почитать Шлее . Автора все хвалят . На торрентах есть его книга по версии qt 4.8 . Текущая версия qt 5.3 .
    Это какой-то пиздец товарищи . Элементарный hello world не собирается . За два года авторы изменили все . Классы , api , названия и пути инклудов ... Как будто понятие совместимости кода им отвратительно в принципе . И они специально решили положить на него толстый йух . wtf ???

    1. Фиг его знает. Думаю, что совместимость только между версиями 4.x, а 5.x уже все по-другому. Текущая версия, кстати, 5.4.1, уже есть 5.5 (beta, кажется). Я всё собирал на 5.4.1.

  5. Это типа такая парадигма программирования ? Давайте каждые 5-7 лет начинать все по-новой ? Ведь это так весело и интересно .
    Если бы версии 4 и 5 были отдельными проектами и развивались параллельно я бы понял . Но если смотреть в архиве
    https://download.qt.io/archive/qt/4.8/
    видно что последняя обнова для 4 версии вышла в июне 14 года . То есть qt5 это все таки по-идее последовательное развитие того же проекта .

    Допустим я немного перекипятился . Совместимость классов между 4 и 5 частью работает . Надругались жестоко в основном над либами и инклудами . Но с qt3 уже вообще похоже нет связи .
    И это при том , что какой-нибудь непривязанный к железу код на c++ 89 года нормально скомпилится и сегодня .

    1. Как минимум, qt поддерживает c++11 уже, тянуть наследие старых плюсов и кучи хаков для древних компиляторов у них, думается, желания нет особого. Да и новые либы появляются, новый функционал в существующие добавляется, вероятно, из-за этого что-то в архитектуре и меняется. Думаю, сложно найти библиотеку или программу (даже если винду взять), которая столько лет тянула бы полную совместимость.

    2. Вы погарячились сильно.
      У меня был проект на 4.8 - пересобрать на 5.х заняло максимум 5 минут. А пара инклюдов - то мелочи. Работает все либо так же, либо лучше.

      По поводу поддержки - тащить за собой кучу не актуальных вещей 10 летней давности - иногда не целесообразно (4.8 был вроде лет 7 актуальным до 5.х).
      4.8 как работыла гуд, так и работает. Хочется - используйте.
      Для обучения более чем достаточно.

      Ui можно создавать как на Qt (в смысле плюсов) так и через Qml, что вам ближе.

      Не знаю насколько сейчас актуально начинать со Шлее. ВОзможно лучше с документации или туториалов. Но то, что там описанно почти все актуально.

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

  7. А вы не планируете еще какие то интересные вещи реальные создать с таким подробным разюором?
    Было бы очень интересно. И я вообще только по вашему примеру и с QML только познакомился)

    1. Я нередко разбираю какие-то новые вещи, но не могу предсказать, какая тема будет для меня интересной в следующий раз +)

      1. Понятно, а то я только пытаюсь познакомится и разабратся с QML и интересно от знатоков увидеть что то новое, что то нетривиальное).
        Может у вас есть какие то готовые примеры или решения создания что то подобное меню, или например по нажатию кнопки вы с какой то скоростью на месте этого окна со здвигом в сторону открываем новое окно, а потмо на новом окне так же нажимаем кнопку и возвращаемся назад?)
        Для меня это не совсем тривиальыне задачи)
        И заранее спасибо)

        1. Всё, что я пока что делал с использованием QML - это тетрис (он выложен здесь в статье) :)
          В составе Qt есть, кстати, очень много разных примеров применения QML, там надолго хватит.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *