Первые шаги с QML

QML — это новый язык разметки для создания пользовательских интерфейсов. Его основная задача — обеспечить возможность простого и быстрого создания приложений с красивым, анимированным интерфейсом.
Не так давно вышла публичная версия. Это означает, что API в целом стабилизировался, и версию можно смело тестировать и использовать.
Declarative UI планируется включить в релиз Qt 4.7, а пока можно найти все необходимые файлы и инструкции по установке на ftp троллей.
В данной статье мне хотелось бы показать, как можно использовать С++ объекты (QObject) в qml.


Первым делом нужно скачать с ftp и собрать qt-4.6.0-declarative.tar.gz. А качестве альтернативы можно использовать уже собранный QtCreator, в котором присутствуют нужные библиотеки
Давайте создадим проект:
Проще всего создать через QtCreator GUI приложение Qt4, в качестве базового класса прекрасно подойдет QWidget

qmltest.pro


SOURCES += main.cpp \
widget.cpp \
myobject.cpp
HEADERS += widget.h \
myobject.h
#не забываем добавить эти два значения, иначе компилятор просто не найдет модуль qt-declarative
QT += declarative \
script
#INCLUDEPATH += #Возможно может пригодится, просто укажите путь до директории include/qt-declarative/

Заголовочный файл нашего виджета

widget.h


#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
class QmlView;
class MyObject;
class Widget : public QWidget
{
  Q_OBJECT
public:
  explicit Widget(QWidget *parent = 0);
private:
  QmlView *view;
  MyObject *object;
private slots:
  void onSceneResized(QSize size);
};

#endif // WIDGET_H

* This source code was highlighted with Source Code Highlighter.


Для начала, неплохо было бы убрать системный заголовок и сделать фон прозрачным:
  setWindowFlags(Qt::FramelessWindowHint);
  setAttribute(Qt::WA_TranslucentBackground);
  setAttribute(Qt::WA_NoSystemBackground);
  view = new QmlView(this);
  view->viewport()->setAutoFillBackground(false);


* This source code was highlighted with Source Code Highlighter.

Теперь инициализируем наш просмотрщик QML и указываем ему путь к файлу, который мы собираемся исполнить
  view->setFocus();
  QString filename = qApp->applicationDirPath() + "/qmlpopups/default/popup.qml";
  view->setUrl(QUrl::fromLocalFile(filename));//url - main.qml


* This source code was highlighted with Source Code Highlighter.

Теперь наступает самое интересное: сделать свойства C++ объекта видимыми из qml файла. Для этого необходимо, чтобы объект наследовался от QObject'а. С помощью макроса Q_PROPERTY свойства делаются доступными из qml объектов и javascript'ов
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)

* This source code was highlighted with Source Code Highlighter.

READ указывает, какой функцией пользоваться для получения значения
WRITE указывает, какая функция используется для изменения
NOTIFY указывает, какой сигнал вызывается при изменении значения, используется в биндингах
Подготовив соответствующим образом объект, мы сможем получить доступ к этим свойствам из qmlя.
  view->rootContext()->setContextProperty("MyObject",object);
  view->rootContext()->setContextProperty("MyText","Hello, QML!");
  view->rootContext()->setContextProperty("Avatar",qApp->applicationDirPath() + "/qmlpopups/default/star.png");


* This source code was highlighted with Source Code Highlighter.

Добавление новых объектов осуществляется через QmlContext, указатель на который возращает функция rootContext(). Можно добавлять как отдельные свойства, так и целые объекты.
Теперь перейдем собственно к qml файлу:
Rectangle {
  id: rect
  width:250
  height: 100
  height: Behavior { NumberAnimation { duration: 1000; easing: "InOutQuad" } }
  color: "transparent"

* This source code was highlighted with Source Code Highlighter.

Код рисует нам прямоугольник 250х100 с прозрачной заливкой. Ничего хитрого здесь не было бы, если бы не странное свойство:
height: Behavior { NumberAnimation { duration: 1000; easing: "InOutQuad" } }
Свойство Behavior указывает нам на поведение объекта при изменении значения height. В данном случае это должна быть анимация. При любом действии, которое устанавливает новое значение высоты, прямоугольник не сразу примет это значение, а лишь выполнив определённую последовательность действий, что очень удобно при создании анимированного гуя.
  BorderImage {
    source: "background.png"
    height: rect.height
    width: rect.width
    border.left: 20
    border.top: 20
    border.bottom: 20
    border.right: 20
  }


* This source code was highlighted with Source Code Highlighter.

В данном блоке демонстрируется создание фонового изображения с обрамлением. И это всё из одной картинки, больше не нужно её разрезать руками, всё будет сделано за вас, нужно лишь указать размеры границ. Думаю многие веб дизайнеры сейчас завидуют.
Чтобы картинка автоматически изменяла свои размеры под размеры прямоугольника, в qml объектах можно использовать property binding, суть его заключается в том, что значение одного параметра привязывается к значению другого и автоматически изменяется при изменении значения оригинального параметра.
Теперь напишем текст
  Text {
    id: title
    text: MyText
    font.pointSize: 14
    wrap: true
    color: "white"

    effect: DropShadow {
     color: "white"
     blurRadius: 2
     offset.x: 0
     offset.y: 0
    }

    anchors.top: rect.top
    anchors.topMargin : 5
    anchors.left: avatar.right
    anchors.leftMargin : 5
  }


* This source code was highlighted with Source Code Highlighter.

Для размещения элементов в qml применяются якоря, в которых указывается положение объекта относительно других объектов, что оказывается весьма удобным. К тексту можно применять различные эффекты, например, эффект тени. Сам текст берётся из контекста, который мы указали ранее. Значение wrap указывает на то, что необходимо делать переносы строк

  Text {    
    id: body
    text: MyObject.text
    font.pointSize: 12
    wrap: true
    color: "white"
    
    //ancors
    anchors.top: title.bottom
    anchors.topMargin: 5
    anchors.right: rect.right
    anchors.rightMargin: 5
    anchors.left: avatar.right
    anchors.leftMargin : 5

    onTextChanged: rect.height = calculateMyHeight();
  }


* This source code was highlighted with Source Code Highlighter.


В этом блоке присутствует слот, который активируется при любом изменении текста, и вызывает javascript функцию, пересчитывающую высоту всего прямоугольника, в котором заключена наша сцена. А текст можно изменять просто вызывая функцию setText у нашего С++ объекта.
  Script {
     function calculateMyHeight() {
       console.log("height : " + (body.y + body.height + 20));
       return (edit.y + edit.height + 20);
  }


* This source code was highlighted with Source Code Highlighter.

В блоке scripts можно описывать javascript'ы, через которые можно взаимодействовать в любыми qml объектами
Оставшийся код можно найти здесь.
В конечном итоге должно получится такое миленькое окошко:

На сегодня всё. С остальными возможностями можно ознакомитmся посмотрев документацию и заглянув в примеры.
PS
Прислали скриншот из Win7, не мог не выложить, для создания размытия используется qtwin


_________
Текст подготовлен в ХабраРедакторе
+40
13 января 2010, 22:10
61

комментарии (44)

0
Xronos #
автодополнение всего этого добра будет или как всегда в голове все держать?
0
Gorthauer87 #
Первоначальная реализация есть в Qt Creator'е, дополнает большую часть свойств. Но моё мнение такое, что, при знакомстве с новой технологией, автокомплит, мощные кодогенераторы и тд, на первых порах скорее вредны. В университетах на первых курсах иногда вообще запрещают RAD использовать.
+10
JStingo #
По моему, как раз наоборот. Первое время автокомплит очень помогает не отвлекаться на орфографию, а сконцентрироваться на сути.
0
Siddthartha #
ну уж нет.
+2
Xronos #
производительность программиста в разы увеличивается, если для студента в университете потратить Nое количество дней на разработку простительно, ибо его время ничего не стоит, то для нормального человека работать без автокомплита — вредительство)
–3
VlK #
по-разному, ох, по-разному…
0
rule #
В последних коммитах на gitorious на проекте qt-creator видел мелькало про доработки QML, допиливают его и доделывают. Там и автокомплит и еще какие-то фенички были. Вобщем полная поддержка будет, вроде даже с предпросмотром всего этого добра (по этому поводу точно сказать не могу, просто было обсуждение, найти его щас не могу, поэтому к чему в итоге пришли — незнаю).

По поводу автозаполнения, год назад я бы с Вами согласился на все 100%. Но так случилось что год назад начал осваивать vim(для комфортной работы в vim пришлось научится в слепую печатать на латинице) и теперь могу даже сомневатся в необходимости автозаполнения. Пользуюсь им только когда не помню точно как называется метод, а просто метод длинной до 10 символов в нацать раз быстрее набрать в слепую, чем нажать комбинацию клавишь для вызова всплывающей подсказки, найти там нужный вариант и клацнуть «Ентер».

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

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

+1
Gorthauer87 #
Автокомплит конечно нужная вещь, сам за это люблю Kdevelop, он очень даже внушительные блоки кода самостоятельно генерит. Но первые шаги лучше делать с минимальным комплитом, а иначе можно не прочуствовать синтаксические конструкции и банально привязаться к IDE на мертво.
В Креаторе вполне рабочий автокомплит для QMLя, но весьма не полный. Лучше уж юзать его с открытой рядом докой.
+9
egor1989 #
НУ ЧТО, ПЕДЕРАСТЫ, МИНУСУЙТЕ!!!
0
energycsdx #
-4 место, видать хочет -1 место
+4
Gorthauer87 #
Предлагаю флешмоб, все плюсуем его дружно, ибо нефиг перед собой такие цели ставить
0
rule #
мне кажется лучше игнорить, само пропадет.
0
nile1 #
не трогаешь — не воняет :)
0
cyberbobs #
Значит, все дружно призываем НЛО :)
+1
egor1989 #
ебаный ты насос, минусуйте сучары
–1
cyberbobs #
Ололо…

Деточка, ну чего тебе неймётся? Что, мама с папой за тройки отругали? Девушка не дала? На работу на нормальную не берут? Так иди дальше качаться в ВОВ, фапать на прон и срать в комментах на анонимных имиджбордах.
0
Gorthauer87 #
Кстати, а тут есть кнопка вызова НЛО? Или куда можно написать, чтобы этому существу сделали экстерминатус?
0
cyberbobs #
Ну вообще в теории можно обратиться к Чипу и Дейлу по ссылке в подвале сайта. Но что-то они пока не спешат на помощь ;)
0
rule #
Да кстати, забыл написать :-), понравился результат, очень даже красивенькое окошечком. :-) (с точки зрения дизайна).
0
Gorthauer87 #
Спасибо :) Делал его для того, чтобы потом использовать как попапы в qutIMе
+1
cyberbobs #
Для начала, неплохо было бы убрать системный заголовок и сделать фон прозрачным:
view->viewport()->setAutoFillBackground(false);

Теперь инициализируем наш просмотрщик QML и указываем ему путь к файлу, который мы собираемся исполнить
view = new QmlView(this);
...


Собственно, если выполнять операции в предложенном вами порядке, до инициализации QmlView мы не дойдем, получив при обращении по не инициализированному указателю Segmentation Fault. Полный исходник не скачивал, вероятно, там все сделано правильно. И тем не менее — поправьте, пожалуйста, в статье :)
+1
Gorthauer87 #
Аха, там всё правильно. Хотел просто всё в одном месте собрать… но чутка промахнулся. Счас пофикшу
0
Indalo #
Тролли молодцы. По-моему QML гораздо нагляднее XAML.

Вообще во многом благодаря Qt я использую С++ без какого-либо дискомфорта, иначе пришлось бы переходить на другие языки.
–1
mace #
Для человеческого глаза нагляднее. А вот если програмно парсить/генерировать — то XML-based код, наверное, все же предпочтительнее.
0
Indalo #
А мне машину не жалко. :) QML вроде использует какой-то стандарт (забыл название), тот же, что и JS.
0
Gorthauer87 #
json
–1
mace #
Я в том смысле, что для XML уже давно существует целый зоопарк библиотек и технологий (XSLT, XPath etc.), которые облегчают работу с ним. Сомневаюсь, что для стандарта QML существует столь полный набор. Впрочем, при желании наверное можно конвертировать QML в XML и наоборот.
0
Gorthauer87 #
Для JSON'а существует достаточно средств разбора и генерации, а QML это далеко ещё не стандарт.
Впрочем он больше похож на эдакий css на стероидах. В будущем наверное и генераторы появятся, но его создавали именно для того, чтобы можно было легко писать прямо на нём, а не использовать внешние инструменты.
0
OS2 #
Автору, спасибо за интересный обзор!
0
energycsdx #
можно ли в qml вставить widget?
–2
wazd #
Конечно нельзя ;) Кнопки для лохов :)
0
energycsdx #
а почему кнопки?
–2
wazd #
Ну любой другой виджет тоже для лохов :)
+2
Gorthauer87 #
Вообще да, можно через QGraphicsProxyWidget
–2
AndreyTS #
Интересно, про XML не слыхали в Qt? Почему выбрали именно что-то вроде JSON?

Так скоро и до XAML дело дойдёт :)
+2
Gorthauer87 #
Что значит не слышали? Для работы с XML имеется достаточно инструментов
Но зачем тут нужен XAML не пойму? Читается он хуже, чем QML, для сравнения нашел тут блог с похожей штукой, но на WPF'е. Для ручного редактирования XAML не так удобен, он куда более многословен.
При этом json проще интегрировать с javascript'ом, его можно даже простым eval'ом парсить.
А я так думаю, что появятся конвертилки WPF <> QML
+2
EuroElessar #
Вы действительно думаете что изобретение велосипедов наподобии XSLT/XAML это хорошая идея?
Я имею в виду велосипеды и костыли, которые позволяют внедрять логику работы в язык разметки, изначально для этого не предназначенный.

С другой стороны имеем Javascript Object Notation, который был спроектирован для передачи данных об объекте и в том числе для передачи логики работы этого объекта (т.е. методов).

Не стоит забывать, что QML предназначен не только для определения внешнего вида, но и для определения логики
+2
Mezomish #
>Интересно, про XML не слыхали в Qt?

Qt-шные ui-файлы — как раз таки XML :)
0
Gorthauer87 #
Прислали тут скрин из винды с некоторыми доработками, можно и такие вещи делать теперь
img193.imageshack.us/img193/1276/pic3nm.png
0
Mezomish #
Спасибо за статью, очень познавательно. Сам начал ковырять новые фишки Qt где-то в сентябре, даже постил статью про Qt Animation Framevork, но до Declarative UI не добрался (хотя хотел, даже собрал его из git-а) — перекинули на другой проект, некогда стало баловаться :)
Поковыряю на досуге.
0
SpeCT #
Простите, а не подскажете, как созданное вами окошко можно подвинуть путём перетаскивания (без заголовка-то)? Где надо написать какой-нибудь обработчик или флаг выставить?

Очень хочется разобраться с возможностями связки QT-QML, и наконец понять – да, QT это то, что мне нужно для разработки эффектных кроссплатформенных UI. Пока что такому осознанию мешает 10летний опыт использования win32 и .net.

PS: Большое спасибо за статью.
0
Longer #
В kde, openbox (и во всём остальном вроде тоже) при зажатом ALT можно за любое место окно перетаскивать, в W7 вроде тоже до этого додумались.
0
Obukhoff #
Ссылки на архив с примером ведут на запаркованный домен.
Уважаемый All — подкиньте файлик qmltest.zip у кого в загашнике остался.
0
Gorthauer87 #
У меня уже нет. Да и с тех пор лучше руководства вышли)

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