qml\qt quick на практике

50
QML\Qt Quick на практике Хомяков Сергей

Upload: platonov-sergey

Post on 22-Jan-2017

1.068 views

Category:

Software


5 download

TRANSCRIPT

Page 1: QML\Qt Quick на практике

QML\Qt Quickна практике

Хомяков Сергей

Page 2: QML\Qt Quick на практике

Какой UI требует рынок?

Page 3: QML\Qt Quick на практике
Page 4: QML\Qt Quick на практике

Требуется тесное взаимодействие между разработчиком и дизайнером

Page 5: QML\Qt Quick на практике

horizontalLayoutWidget->setGeometry(QRect(10, 0, 501, 51)); horizontalLayout = new QHBoxLayout(horizontalLayoutWidget); horizontalLayout->setSpacing(6); horizontalLayout->setContentsMargins(11, 11, 11, 11); horizontalLayout->setContentsMargins(0, 0, 0, 0); pushButton_2 = new QPushButton(horizontalLayoutWidget); horizontalLayout->addWidget(pushButton_2); pushButton_4 = new QPushButton(horizontalLayoutWidget); horizontalLayout->addWidget(pushButton_4); pushButton_3 = new QPushButton(horizontalLayoutWidget); horizontalLayout->addWidget(pushButton_3); pushButton = new QPushButton(horizontalLayoutWidget); horizontalLayout->addWidget(pushButton); horizontalSlider = new QSlider(centralWidget); horizontalSlider->setGeometry(QRect(10, 60, 501, 16)); horizontalSlider->setOrientation(Qt::Horizontal); textEdit = new QTextEdit(centralWidget); textEdit->setGeometry(QRect(20, 90, 481, 201)); MainWindow->setCentralWidget(centralWidget);

Page 6: QML\Qt Quick на практике

RowLayout { anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.topMargin: 18 Button { text: qsTr("Button 1") } Button { text: qsTr("Button 2") } Button { text: qsTr("Button 3") } Button { text: qsTr("Button 4") } }

Slider { x: 143; y: 57 width: 355; height: 28 }

TextArea { x: 142; y: 105 width: 355; height: 150 }

Page 7: QML\Qt Quick на практике

Что такое QML?

Page 8: QML\Qt Quick на практике

QML это JSON-подобный декларативный язык программирования, основанный на JavaScript, использующий С++ API для интеграции с Qt

Qt Quick это scenegraph-based UI framework, использующий в качестве языка программирования QML и позиционирующий себя как инструмент для быстрой разработки и прототипирования

Page 9: QML\Qt Quick на практике

Где уместно использовать Qt Quick?

Там где вы уже используете Qt

Там где требуется не стандартный (вычурный) UI

Там где необходим кросплатформенный “look and feel”

Там где есть постоянно меняющиеся требования к дизайну и бизнес-

логике

Page 10: QML\Qt Quick на практике

Hello World

Page 11: QML\Qt Quick на практике

Hello World

Page 12: QML\Qt Quick на практике

Hello World

Page 13: QML\Qt Quick на практике

Hello World

import QtQuick 2.0

Rectangle { id: root

width: 120; height: 240 color: "#D8D8D8"

Image { id: world x: (parent.width - width)/2 y: 40 source: 'assets/world.png' }

Text { y: world.y + world.height + 20 width: root.width horizontalAlignment: Text.AlignHCenter text: 'Hello World' }}

Page 14: QML\Qt Quick на практике

import QtQuick 2.2

Rectangle { id: photo objectName: "photo" property bool thumbnail: false property alias image: photoImage.source

signal clicked(); color: "gray" x: 20; y: 20 height: 150 width: { if(photoImage.width > 200) { photoImage.width; } else { 200; } } function doSomething(dx) { return dx + photoImage.width; } onHeightChanged: {

var tmp = doSomething(photo.height);console.log( tmp );

}

QtObject { id: p_attr readonly property color borderSelectedColor: "red" readonly property color borderUnSelectedColor: "black" property int animationDuration: 200 }

Rectangle { id: border anchors.centerIn: parent Image { id: photoImage; anchors.centerIn: parent } } MouseArea { anchors.fill: parent onClicked: photo.clicked(); } states:[ State { name: "Selected" PropertyChanges { target: border; color: p_attr.borderSelectedColor } }, State { name: "UnSelected" PropertyChanges { target: border; color: p_attr.borderUnSelectedColor } } ] transitions: Transition { to: "Selected" ColorAnimation { target: border; duration: p_attr.animationDuration } }}

Page 15: QML\Qt Quick на практике

import QtQuick 2.2

Rectangle { id: photo objectName: "photo" property bool thumbnail: false property alias image: photoImage.source

signal clicked(); color: "gray" x: 20; y: 20 height: 150 width: { if(photoImage.width > 200) { photoImage.width; } else { 200; } } function doSomething(dx) { return dx + photoImage.width; } onHeightChanged: {

var tmp = doSomething(photo.height);console.log( tmp );

}

QtObject { id: p_attr readonly property color borderSelectedColor: "red" readonly property color borderUnSelectedColor: "black" property int animationDuration: 200 }

Rectangle { id: border anchors.centerIn: parent Image { id: photoImage; anchors.centerIn: parent } } MouseArea { anchors.fill: parent onClicked: photo.clicked(); } states:[ State { name: "Selected" PropertyChanges { target: border; color: p_attr.borderSelectedColor } }, State { name: "UnSelected" PropertyChanges { target: border; color: p_attr.borderUnSelectedColor } } ] transitions: Transition { to: "Selected" ColorAnimation { target: border; duration: p_attr.animationDuration } }}

Page 16: QML\Qt Quick на практике

import QtQuick 2.2

Rectangle { id: photo objectName: "photo" property bool thumbnail: false property alias image: photoImage.source

signal clicked(); color: "gray" x: 20; y: 20 height: 150 width: { if(photoImage.width > 200) { photoImage.width; } else { 200; } } function doSomething(dx) { return dx + photoImage.width; } onHeightChanged: {

var tmp = doSomething(photo.height);console.log( tmp );

}

QtObject { id: p_attr readonly property color borderSelectedColor: "red" readonly property color borderUnSelectedColor: "black" property int animationDuration: 200 }

Rectangle { id: border anchors.centerIn: parent Image { id: photoImage; anchors.centerIn: parent } } MouseArea { anchors.fill: parent onClicked: photo.clicked(); } states:[ State { name: "Selected" PropertyChanges { target: border; color: p_attr.borderSelectedColor } }, State { name: "UnSelected" PropertyChanges { target: border; color: p_attr.borderUnSelectedColor } } ] transitions: Transition { to: "Selected" ColorAnimation { target: border; duration: p_attr.animationDuration } }}

Page 17: QML\Qt Quick на практике

import QtQuick 2.2

Rectangle { id: photo objectName: "photo" property bool thumbnail: false property alias image: photoImage.source

signal clicked(); color: "gray" x: 20; y: 20 height: 150 width: { if(photoImage.width > 200) { photoImage.width; } else { 200; } } function doSomething(dx) { return dx + photoImage.width; } onHeightChanged: {

var tmp = doSomething(photo.height);console.log( tmp );

}

QtObject { id: p_attr readonly property color borderSelectedColor: "red" readonly property color borderUnSelectedColor: "black" property int animationDuration: 200 }

Rectangle { id: border anchors.centerIn: parent Image { id: photoImage; anchors.centerIn: parent } } MouseArea { anchors.fill: parent onClicked: photo.clicked(); } states:[ State { name: "Selected" PropertyChanges { target: border; color: p_attr.borderSelectedColor } }, State { name: "UnSelected" PropertyChanges { target: border; color: p_attr.borderUnSelectedColor } } ] transitions: Transition { to: "Selected" ColorAnimation { target: border; duration: p_attr.animationDuration } }}

Page 18: QML\Qt Quick на практике

import QtQuick 2.2

Rectangle { id: photo objectName: "photo" property bool thumbnail: false property alias image: photoImage.source

signal clicked(); color: "gray" x: 20; y: 20 height: 150 width: { if(photoImage.width > 200) { photoImage.width; } else { 200; } } function doSomething(dx) { return dx + photoImage.width; } onHeightChanged: {

var tmp = doSomething(photo.height);console.log( tmp );

}

QtObject { id: p_attr readonly property color borderSelectedColor: "red" readonly property color borderUnSelectedColor: "black" property int animationDuration: 200 }

Rectangle { id: border anchors.centerIn: parent Image { id: photoImage; anchors.centerIn: parent } } MouseArea { anchors.fill: parent onClicked: photo.clicked(); } states:[ State { name: "Selected" PropertyChanges { target: border; color: p_attr.borderSelectedColor } }, State { name: "UnSelected" PropertyChanges { target: border; color: p_attr.borderUnSelectedColor } } ] transitions: Transition { to: "Selected" ColorAnimation { target: border; duration: p_attr.animationDuration } }}

Page 19: QML\Qt Quick на практике

import QtQuick 2.2

Rectangle { id: photo objectName: "photo" property bool thumbnail: false property alias image: photoImage.source

signal clicked(); color: "gray" x: 20; y: 20 height: 150 width: { if(photoImage.width > 200) { photoImage.width; } else { 200; } } function doSomething(dx) { return dx + photoImage.width; } onHeightChanged: {

var tmp = doSomething(photo.height);console.log( tmp );

}

QtObject { id: p_attr readonly property color borderSelectedColor: "red" readonly property color borderUnSelectedColor: "black" property int animationDuration: 200 }

Rectangle { id: border anchors.centerIn: parent Image { id: photoImage; anchors.centerIn: parent } } MouseArea { anchors.fill: parent onClicked: photo.clicked(); } states:[ State { name: "Selected" PropertyChanges { target: border; color: p_attr.borderSelectedColor } }, State { name: "UnSelected" PropertyChanges { target: border; color: p_attr.borderUnSelectedColor } } ] transitions: Transition { to: "Selected" ColorAnimation { target: border; duration: p_attr.animationDuration } }}

Page 20: QML\Qt Quick на практике

import QtQuick 2.2

Rectangle { id: photo objectName: "photo" property bool thumbnail: false property alias image: photoImage.source

signal clicked(); color: "gray" x: 20; y: 20 height: 150 width: { if(photoImage.width > 200) { photoImage.width; } else { 200; } } function doSomething(dx) { return dx + photoImage.width; } onHeightChanged: {

var tmp = doSomething(photo.height);console.log( tmp );

}

QtObject { id: p_attr readonly property color borderSelectedColor: "red" readonly property color borderUnSelectedColor: "black" property int animationDuration: 200 }

Rectangle { id: border anchors.centerIn: parent Image { id: photoImage; anchors.centerIn: parent } } MouseArea { anchors.fill: parent onClicked: photo.clicked(); } states:[ State { name: "Selected" PropertyChanges { target: border; color: p_attr.borderSelectedColor } }, State { name: "UnSelected" PropertyChanges { target: border; color: p_attr.borderUnSelectedColor } } ] transitions: Transition { to: "Selected" ColorAnimation { target: border; duration: p_attr.animationDuration } }}

Page 21: QML\Qt Quick на практике

import QtQuick 2.2

Rectangle { id: photo objectName: "photo" property bool thumbnail: false property alias image: photoImage.source

signal clicked(); color: "gray" x: 20; y: 20 height: 150 width: { if(photoImage.width > 200) { photoImage.width; } else { 200; } } function doSomething(dx) { return dx + photoImage.width; } onHeightChanged: {

var tmp = doSomething(photo.height);console.log( tmp );

}

QtObject { id: p_attr readonly property color borderSelectedColor: "red" readonly property color borderUnSelectedColor: "black" property int animationDuration: 200 }

Rectangle { id: border anchors.centerIn: parent Image { id: photoImage; anchors.centerIn: parent } } MouseArea { anchors.fill: parent onClicked: photo.clicked(); } states:[ State { name: "Selected" PropertyChanges { target: border; color: p_attr.borderSelectedColor } }, State { name: "UnSelected" PropertyChanges { target: border; color: p_attr.borderUnSelectedColor } } ] transitions: Transition { to: "Selected" ColorAnimation { target: border; duration: p_attr.animationDuration } }}

Page 22: QML\Qt Quick на практике

import QtQuick 2.2

Rectangle { id: photo objectName: "photo" property bool thumbnail: false property alias image: photoImage.source

signal clicked(); color: "gray" x: 20; y: 20 height: 150 width: { if(photoImage.width > 200) { photoImage.width; } else { 200; } } function doSomething(dx) { return dx + photoImage.width; } onHeightChanged: {

var tmp = doSomething(photo.height);console.log( tmp );

}

QtObject { id: p_attr readonly property color borderSelectedColor: "red" readonly property color borderUnSelectedColor: "black" property int animationDuration: 200 }

Rectangle { id: border anchors.centerIn: parent Image { id: photoImage; anchors.centerIn: parent } } MouseArea { anchors.fill: parent onClicked: photo.clicked(); } states:[ State { name: "Selected" PropertyChanges { target: border; color: p_attr.borderSelectedColor } }, State { name: "UnSelected" PropertyChanges { target: border; color: p_attr.borderUnSelectedColor } } ] transitions: Transition { to: "Selected" ColorAnimation { target: border; duration: p_attr.animationDuration } }}

Page 23: QML\Qt Quick на практике

// Circle.qml

import QtQuick 2.0

Rectangle { property real diameter : 30 width: diameter height: diameter radius: diameter}

import QtQuick 2.0

Rectangle { width: 120; height: 240 Column { anchors.fill: parent Repeater { model: 3

Circle { color: "blue" diameter: 90 }

} }}

Page 24: QML\Qt Quick на практике

Позиционирование и выравнивание

Page 25: QML\Qt Quick на практике

Якоря бывают двух видов:-ссылающиеся на элемент (centerIn, fill)-ссылающиеся на другой якорь ( left, right, top, bottom, …. )

Page 26: QML\Qt Quick на практике

import QtQuick 2.0

Rectangle { id: root width: 120; height: 240 color: "#D8D8D8"

Image { id: world anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top anchors.topMargin: 40 source: 'assets/world.png' }

Text { anchors.top: world.bottom anchors.topMargin: 20 anchors.horizontalCenter: world.horizontalCenter text: 'Hello World' }}

Hello World

Page 27: QML\Qt Quick на практике

Причём тут С++?

Page 28: QML\Qt Quick на практике

С++ API позволяет:

– экспортировать в QML C++ обьекты наследованные от QObject

– экспортировать в QML не визуальные типы

– классы на основе QQuickPaintedItem для визуальных элементов с

поддержкой QPainter

– классы на основе QQuickItem для визуальных элементов сцены

Page 29: QML\Qt Quick на практике

Экспорт С++ объекта

Page 30: QML\Qt Quick на практике

class User : public QObject{

Q_OBJECTQ_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)Q_PROPERTY(int age READ age WRITE setAge NOTIFY ageChanged)

public:User(const QString &name, int age, QObject *parent = 0);

...}

Page 31: QML\Qt Quick на практике

void main( int argc, char* argv[] ) {...User *currentUser = new User("Alice", 29);QQuickView *view = new QQuickView;QQmlContext *context = view->engine()->rootContext();context->setContextProperty("currentUser", currentUser);...

}

Page 32: QML\Qt Quick на практике

void main( int argc, char* argv[] ) {...User *currentUser = new User("Alice", 29);QQuickView *view = new QQuickView;QQmlContext *context = view->engine()->rootContext();context->setContextProperty("currentUser", currentUser);...

}

Text { text : currentUser.name }

Page 33: QML\Qt Quick на практике

Экспорт С++ типа

Page 34: QML\Qt Quick на практике

#include <QObject>class CustomTimer : public QObject{ Q_OBJECT Q_PROPERTY( int interval READ interval WRITE setInterval NOTIFY intervalChanged )public: CustomTimer(QObject *parent = 0); int interval() const; public slots: void start(); void stop(); void setInterval(int arg);signals: void intervalChanged(int arg); void timeout();private: QTimer* m_timer; int m_interval;};

Page 35: QML\Qt Quick на практике

#include <QGuiApplication>#include <QQuickView>#include "CustomTimer.h"int main(int argc, char *argv[]){ QGuiApplication app(argc, argv); qmlRegisterType<CustomTimer>("CustomComponents", 1, 0, "CustomTimer"); QQuickView view; view.setSource(QUrl("qrc:///main.qml")); view.show(); return app.exec();}

Page 36: QML\Qt Quick на практике

import CustomComponents 1.0

Rectangle { id: root Component.onCompleted: { timer.start(); } …….. CustomTimer { id: timer interval: 3000 onTimeout: { console.log( "Timer timeout!" ); root.color = "red"; } }

}

Page 37: QML\Qt Quick на практике

Экспорт QQuickPaintedltem

Page 38: QML\Qt Quick на практике

#include <QQuickPaintedItem>class EllipseItem : public QQuickPaintedItem{ Q_OBJECTpublic: EllipseItem(QQuickItem *parent = 0); void paint(QPainter *painter);};

void EllipseItem::paint(QPainter *painter){ const qreal halfPenWidth = qMax(painter->pen().width() / 2.0, 1.0); QRectF rect = boundingRect(); rect.adjust(halfPenWidth, halfPenWidth, -halfPenWidth, -halfPenWidth); painter->drawEllipse(rect);}

Page 39: QML\Qt Quick на практике

#include <QGuiApplication>#include <QQuickView>#include "EllipseItem.h"int main(int argc, char *argv[]){ QGuiApplication app(argc, argv); qmlRegisterType<EllipseItem>("CustomComponents", 1, 0, "Ellipse"); QQuickView view; view.setSource(QUrl("qrc:///main.qml")); view.show(); return app.exec();}

Page 40: QML\Qt Quick на практике

import CustomComponents 1.0

Rectangle { id: root EllipseItem {

anchors.centerIn: parent width: 64 height: 48

} }

Page 41: QML\Qt Quick на практике

Экспорт QQuickltem

Page 42: QML\Qt Quick на практике

#include <QQuickItem>#include <QSGGeometry>#include <QSGFlatColorMaterial>class TriangleItem : public QQuickItem{ Q_OBJECTpublic: TriangleItem(QQuickItem *parent = 0);protected: QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *data);private: QSGGeometry m_geometry; QSGFlatColorMaterial m_material;};

Page 43: QML\Qt Quick на практике

QSGNode *TriangleItem::updatePaintNode(QSGNode *n, UpdatePaintNodeData *){ QSGGeometryNode *node = static_cast<QSGGeometryNode *>(n); if (!node) node = new QSGGeometryNode(); QSGGeometry::Point2D *v = m_geometry.vertexDataAsPoint2D(); const QRectF rect = boundingRect(); v[0].x = rect.left(); v[0].y = rect.bottom(); v[1].x = rect.left() + rect.width()/2; v[1].y = rect.top(); v[2].x = rect.right(); v[2].y = rect.bottom(); node->setGeometry(&m_geometry); node->setMaterial(&m_material); return node;}

Page 44: QML\Qt Quick на практике

QSGNode * QQuickCustomItem::updatePaintNode(QSGNode * node, UpdatePaintNodeData * nodedata){

TexureHolderNode * texture_node = static_cast<TexureHolderNode *>(node);if (!texture_node) texture_node = new TexureHolderNode();if (texture_node->fbo_ && (texture_node->fbo_->width() != width() || texture_node->fbo_->height() != height())){

texture_node->fbo_.reset();}if (texture_node->fbo_.isNull()){

QSize fboSize(qMax<int>(1, int(width())), qMax<int>(1, int(height())));QOpenGLFramebufferObjectFormat format;texture_node->fbo_.reset(new QOpenGLFramebufferObject(fboSize, format));texture_node->setTexture( window()->createTextureFromId( texture_node->fbo_->texture(), texture_node->fbo_->size(), 0) );texture_node->setRect(0, 0, width(), height());redraw_texture_needed_ = true;

}if (redraw_texture_needed_){

redraw_texture_needed_ = false;texture_node->fbo_->bind();{

paintGL();}texture_node->fbo_->bindDefault();texture_node->markDirty(QSGNode::DirtyMaterial);

}

return texture_node;}

class TexureHolderNode: public QSGSimpleTextureNode

{ public:

TexureHolderNode() {}QScopedPointer<QOpenGLFramebufferObject> fbo_;

};

Page 45: QML\Qt Quick на практике
Page 46: QML\Qt Quick на практике

https://github.com/2gis/qtandroidextensions

Page 47: QML\Qt Quick на практике

Что нужно оставлять в плюсах, что лучше перенести в QML?

Page 48: QML\Qt Quick на практике

Инструменты разработки и отладки

Page 49: QML\Qt Quick на практике

Autopilot-Qt5QtCreator GammaRay Squish

– qt.io/ru/download-open-source

– kdab.com/gammaray

– froglogic.com/squish

– wiki.ubuntu.com/Touch/Testing/Autopilot

Page 50: QML\Qt Quick на практике

Вопросы?

Хомяков Сергей[email protected]