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

Post on 22-Jan-2017

1.054 Views

Category:

Software

5 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

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

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

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

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);

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 }

Что такое QML?

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

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

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

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

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

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

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

логике

Hello World

Hello World

Hello World

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' }}

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 } }}

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 } }}

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 } }}

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 } }}

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 } }}

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 } }}

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 } }}

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 } }}

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 } }}

// 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 }

} }}

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

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

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

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

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

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

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

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

поддержкой QPainter

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

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

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);

...}

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);...

}

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 }

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

#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;};

#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();}

import CustomComponents 1.0

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

}

Экспорт QQuickPaintedltem

#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);}

#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();}

import CustomComponents 1.0

Rectangle { id: root EllipseItem {

anchors.centerIn: parent width: 64 height: 48

} }

Экспорт QQuickltem

#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;};

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;}

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_;

};

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

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

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

Autopilot-Qt5QtCreator GammaRay Squish

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

– kdab.com/gammaray

– froglogic.com/squish

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

Вопросы?

Хомяков Сергейs.homyakov@2gis.ru

top related