使用C++拓展QML 类型及Property binding!
来源:互联网 发布:帝国cms免费吗 编辑:程序博客网 时间:2024/05/16 14:29
我们知道QML虽然是很强大的,但是有时我们觉得它有些功能还是需要C++来拓展的话,这时我们可以使用IDE提供的plugin架构来创建一个新的plugin。这个plugin可以在QML里直接调用。它的使用就像先前定义好的控件一样。首先我们来看一下我们最终设计的界面。这里是一个交通灯的示范例程:
这时,我们可以关闭项目再打开项目,或者直接在项目框中点击右键,并运行“Run CMake”以使刚加入的文件在项目框中可见。
我们下面来做一个简单的实验,看TrafficLight是否被正确地调用。修改“TrafficLight.qml”文件如下:
在Desktop上运行,我们可以看到:
在这里我们使用了一个"Column"的layout管理器,它可以使得在它之内部件(Component)从上到下进行显示和管理。如果屏幕的尺寸发生变化,它也会帮我们自动适配及调整。你可以看出我们创建了从上到下的三个“红”,“黄”及“绿”的交通灯。你们也可看到我在这里也使用了一个背景的图片以使得显示效果更加逼真。如果开发者没有这个图片也没有关系。我在下面贴出来(右边的图)。如果确实没有,也没关系。运行时可能看不到背景的图片而已。开发者可以把图片考到和“trafficlight.qml”相同的目录。
在这里我们定义了4个不同的状态"red_on", "red_yellow_on", "yellow_on" 及“green_on"。这几个状态显然我们常见的几个交通灯的状况。在每个状态下,我们可以看到各个灯的”开”及”关"的情况。
在这里我们定义了无论从哪种状态“*”到哪种状态“*”,我们变化的时间是1000毫秒,同时要使得它的scale,及颜色发生相应的渐变。这样可以产生我们所希望的动画效果。
运行效果如下:
这里显示的是几个交通灯变化的画面。它们也同时对应我们现实生活中的交通灯变化的几个状态。
在这篇文章里,我们将学到如下的东西:
- 学习怎么制作一个plugin
- 学习property binding
- 学习QML的状态(state)及过渡(transition)
- 学习怎么制作Component
1) 创建一个基本的应用
首先我们启动Qt Creator IDE,然后选择如下所示的template (App with QML extension Library):
创建一个称作"TrafficLight"的项目:
同时也把应用的名字设定为“Light":
然后,我们按IDE提示的步骤完成以后的过程创建出我们的最原始的一个template应用。我们可以开始在desktop及"armhf"的环境中运行。如果我们还有问题,这可能是我们的安装程序有些问题。请参考我们的SDK安装文章进行修正。
2) 完成TrafficLight plugin
我们知道QML提供了很好的图形控件。QML有一个称作LinearGradient的Gradient,但他不是我们想要的RadialGradient。经过寻扎,我们在C++中找到相应的QRadialGradient类,它可以实现我们想要的功能。我们怎来把它使用到我们的C++应用中呢?
首先我们找到项目中的文件目录“TrafficLight/backend/modules/Light”,创建“trafficlight.h"及“trafficlight.cpp"文件,并输入如下的代码
#ifndef TRAFFICLIGHT_H#define TRAFFICLIGHT_H#include <QtQuick/QQuickPaintedItem>#include <QColor>class TrafficLight : public QQuickPaintedItem{ Q_OBJECT Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)public: explicit TrafficLight(QQuickItem *parent = 0); void paint(QPainter *painter); QColor color() const; void setColor(const QColor &color);signals: void colorChanged();public slots:private: QColor m_color;};#endif // TRAFFICLIGHT_H
<pre style="margin-top: 0px; margin-bottom: 0px;"><!--StartFragment--><span style=" color:#000080;"></span>
#include <QPainter>
#include <QRadialGradient>
#include "trafficlight.h"
TrafficLight::TrafficLight(QQuickItem *parent)
: QQuickPaintedItem(parent)
{
}
QColor TrafficLight::color() const
{
return m_color;
}
void TrafficLight::setColor(const QColor &color)
{
if ( color == m_color )
return;
else {
m_color = color;
update(); // repaint with the new color
emit colorChanged();
}
}
void TrafficLight::paint(QPainter *painter)
{
QRectF rect(boundingRect());
QPen pen;
pen.setWidthF( 0 );
pen.setColor(m_color);
painter->setPen( pen );
QRadialGradient g( rect.width()/2, rect.height()/2,
rect.width()/2, rect.width()/2, height()/2 );
g.setColorAt( 0.0, Qt::white );
g.setColorAt( 1.0, m_color );
painter->setBrush( g );
painter->drawEllipse(rect);
}这里我们定义了一个称作为“TrafficLight”的类。根据不同的颜色,用它来画一个“QRadialGradient”。我们可以看到在这个类中我们定义了一个称作“color"的property。
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
在下面的QML语言中,我们可以直接通过绑定这个property,也可以对它进行修改从而使得界面发生改变。
我们找到"TrafficLight/backend/CMakeLists.txt"文件,并加入如下的语句:
set( Lightbackend_SRCS modules/Light/backend.cpp modules/Light/mytype.cpp modules/Light/trafficlight.cpp)
这时,我们可以关闭项目再打开项目,或者直接在项目框中点击右键,并运行“Run CMake”以使刚加入的文件在项目框中可见。
找到“backend.cpp"文件,并加入如下语句:
#include <QtQml>#include <QtQml/QQmlContext>#include "backend.h"#include "mytype.h"#include "trafficlight.h"void BackendPlugin::registerTypes(const char *uri){ Q_ASSERT(uri == QLatin1String("Light")); qmlRegisterType<MyType>(uri, 1, 0, "MyType"); qmlRegisterType<TrafficLight>(uri, 1, 0, "TrafficLight");}void BackendPlugin::initializeEngine(QQmlEngine *engine, const char *uri){ QQmlExtensionPlugin::initializeEngine(engine, uri);}
这里注册的目的是为了让“TrafficLight”类在QML文件中可以被实例化。第二个"TrafficLight"可以是任何你喜欢的名字,只要它可以和QML中的引用对应即可。
这样我们基本上完成了对plugin的设计。我们这时可以编译一下看一下有什么问题。如果没有的话,我们可以直接进入下面的章节。
3)在QML中引用TrafficLight类型
我们下面来做一个简单的实验,看TrafficLight是否被正确地调用。修改“TrafficLight.qml”文件如下:
import QtQuick 2.0import Ubuntu.Components 0.1import "ui"import Light 1.0MainView { // objectName for functional testing purposes (autopilot-qt5) objectName: "mainView" // Note! applicationName needs to match the "name" field of the click manifest applicationName: "com.ubuntu.developer.liu-xiao-guo.TrafficLight" /* This property enables the application to change orientation when the device is rotated. The default is false. */ //automaticOrientation: true width: units.gu(100) height: units.gu(75) TrafficLight{ id: redlight width: 100 height: 100 color:"red" }}
在Desktop上运行,我们可以看到:
我们可以看到plugin是真的被调用了。我们可以改变图形的位置或颜色来看看有什么变化等。
4)应用设计
通过修改"TrafficLight.qml"文件,我们首先来看一看我们设计的程序如下:
import QtQuick 2.0import Ubuntu.Components 0.1import "ui"import Light 1.0MainView { // objectName for functional testing purposes (autopilot-qt5) objectName: "mainView" // Note! applicationName needs to match the "name" field of the click manifest applicationName: "com.ubuntu.developer.liu-xiao-guo.TrafficLight" /* This property enables the application to change orientation when the device is rotated. The default is false. */ //automaticOrientation: true width: units.gu(100) height: units.gu(75) Page { id:main anchors.fill: parent property int radius: 155 Image{ anchors.horizontalCenter: parent.horizontalCenter height:parent.height source: "light2.png" fillMode: Image.PreserveAspectFit Column { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter spacing: 28 TrafficLight{ id: redlight width: main.radius height: main.radius color:"red" } TrafficLight{ id: yellowlight width: main.radius height: main.radius color:"yellow" } TrafficLight{ id: greenlight width: main.radius height: main.radius color:"green" } } } }}
在这里我们使用了一个"Column"的layout管理器,它可以使得在它之内部件(Component)从上到下进行显示和管理。如果屏幕的尺寸发生变化,它也会帮我们自动适配及调整。你可以看出我们创建了从上到下的三个“红”,“黄”及“绿”的交通灯。你们也可看到我在这里也使用了一个背景的图片以使得显示效果更加逼真。如果开发者没有这个图片也没有关系。我在下面贴出来(右边的图)。如果确实没有,也没关系。运行时可能看不到背景的图片而已。开发者可以把图片考到和“trafficlight.qml”相同的目录。
5)加入状态及过渡
我们知道,上面显示的情况显然不是我们常见的交通灯的情况。现在我们来加入状态来在不同的情况下,让各个等在不同的状态下进行关掉或熄灭。程序如下:
states: [ State { name: "red_on" PropertyChanges { target: redlight color:"red" scale: 1.0 } PropertyChanges { target: greenlight color: "black" } PropertyChanges { target: yellowlight color: "black" } }, State { name: "red_yellow_on" PropertyChanges { target: redlight color: "red" } PropertyChanges { target: yellowlight color: "yellow" } PropertyChanges { target: greenlight color: "black" } }, State { name: "green_on" PropertyChanges { target: redlight color: "black" } PropertyChanges { target: yellowlight color: "black" } PropertyChanges { target: greenlight color: "green" } }, State { name: "yellow_on" PropertyChanges { target: redlight color: "black" } PropertyChanges { target: yellowlight color: "yellow" } PropertyChanges { target: greenlight color: "black" } } ]
在这里我们定义了4个不同的状态"red_on", "red_yellow_on", "yellow_on" 及“green_on"。这几个状态显然我们常见的几个交通灯的状况。在每个状态下,我们可以看到各个灯的”开”及”关"的情况。
QML也同时提供给我们在不同状态之间进行转换时的动画效果。我们可以通过过渡来实现:
transitions: [ Transition { from: "*" to: "*" PropertyAnimation { target: redlight properties: "scale, color" duration: 1000 easing.type: Easing.InQuad } PropertyAnimation { target: greenlight properties: "scale, color" duration: 1000 easing.type: Easing.InQuad } PropertyAnimation { target: yellowlight properties: "scale, color" duration: 1000 easing.type: Easing.InQuad } } ]
在这里我们定义了无论从哪种状态“*”到哪种状态“*”,我们变化的时间是1000毫秒,同时要使得它的scale,及颜色发生相应的渐变。这样可以产生我们所希望的动画效果。
注意这两段代码必须是加到"Column"所在的块中。
6)加入逻辑使得他们在不同的状态之间转换
我们知道只通过简单的状态定义并不能使得应该在不同的状态之间转换。我们必须定义一个逻辑或事件使得它们在某种条件下转换。对于我们的例程,我们可以使用一个Timer来实现:
Timer { interval: 1000 running: true repeat: true property int count: 0 onTriggered: { if (parent.state == "red_on" && count >= 5) { parent.state = "red_yellow_on" count = 0 } else if ( parent.state == "red_yellow_on" ) { parent.state = "green_on" count++ } else if ( parent.state == "green_on" && count >= 5 ) { parent.state = "yellow_on" count ++ } else if ( parent.state == "yellow_on" ) { parent.state = "red_on" count = 0 } else { count++ } } }
这个Timer每一秒触发一次,onTriggered是以个callback方法。通过这个事件我们可以使得程序在不同的状态下转换。
至此,我们这个部分的程序已经设计完成。整个完整的代码可以在如下的地址下载:
bzr branch lp:~liu-xiao-guo/debiantrial/trafficlight
7)为程序设计Component
我们刚才设计的程序在某种程度上能够完成我们的功能。但是,设想一下,如果我们想在程序中需要更多的交通灯怎么办呢?我们可以把刚才设计的程序改一下,重新包装成一个Component。这样这个控件在许多的程序中可以复用这个控件。
在"TrafficLight.qml"所在的目录中,我们重新生成一个新的文件叫做”MyLight.qml"。这里记得文件的名称一定要大写。同时我们删除在"TrafficLight.qml"中相应的部分的设计。把相关的代码移过去。
这样重新生成的代码如下:
import QtQuick 2.0import Ubuntu.Components 0.1import "ui"MainView { // objectName for functional testing purposes (autopilot-qt5) objectName: "mainView" // Note! applicationName needs to match the "name" field of the click manifest applicationName: "com.ubuntu.developer.liu-xiao-guo.TrafficLight" /* This property enables the application to change orientation when the device is rotated. The default is false. */ //automaticOrientation: true width: units.gu(120) height: units.gu(80) Page { id:main anchors.fill: parent Row { id: myrow anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter spacing: units.gu(5) MyLight { id:light1 width: main.width/5 height: width*3 } MyLight { id:light2 width: main.width/5 height: width*3 } MyLight { id:light3 width: main.width/5 height: width*3 } } }}
MyLight.qml 代码
import QtQuick 2.0import Ubuntu.Components 0.1import Light 1.0Item { width: units.gu(100) height: units.gu(75) Rectangle { id: background anchors.fill: parent color: "black" property int size: width*0.7 Column { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter spacing: units.gu(3) TrafficLight{ id: redlight width: background.size height: background.size color:"red" } TrafficLight{ id: yellowlight width: background.size height: background.size color:"yellow" } TrafficLight{ id: greenlight width: background.size height: background.size color:"green" } state: "red_on" states: [ State { name: "red_on" PropertyChanges { target: redlight color:"red" scale: 1.0 } PropertyChanges { target: greenlight color: "black" } PropertyChanges { target: yellowlight color: "black" } }, State { name: "red_yellow_on" PropertyChanges { target: redlight color: "red" } PropertyChanges { target: yellowlight color: "yellow" } PropertyChanges { target: greenlight color: "black" } }, State { name: "green_on" PropertyChanges { target: redlight color: "black" } PropertyChanges { target: yellowlight color: "black" } PropertyChanges { target: greenlight color: "green" } }, State { name: "yellow_on" PropertyChanges { target: redlight color: "black" } PropertyChanges { target: yellowlight color: "yellow" } PropertyChanges { target: greenlight color: "black" } } ] transitions: [ Transition { from: "*" to: "*" PropertyAnimation { target: redlight properties: "scale, color" duration: 1000 easing.type: Easing.InQuad } PropertyAnimation { target: greenlight properties: "scale, color" duration: 1000 easing.type: Easing.InQuad } PropertyAnimation { target: yellowlight properties: "scale, color" duration: 1000 easing.type: Easing.InQuad } } ] Timer { interval: 1000 running: true repeat: true property int count: 0 onTriggered: { if (parent.state == "red_on" && count >= 5) { parent.state = "red_yellow_on" count = 0 } else if ( parent.state == "red_yellow_on" ) { parent.state = "green_on" count++ } else if ( parent.state == "green_on" && count >= 5 ) { parent.state = "yellow_on" count ++ } else if ( parent.state == "yellow_on" ) { parent.state = "red_on" count = 0 } else { count++ } } } } }}
运行效果如下:
所有的源码可以在如下地方找到:
https://github.com/liu-xiao-guo/trafficlight_app
0 0
- 使用C++拓展QML 类型及Property binding!
- QML类型说明-Binding
- QML Property Binding with QT C++
- QML的property所支持的类型
- QML的 property 支持的类型
- 如何使用软件的方法来查找一个QML的类型的所有的property
- QML之使用C++自定义QML类型(一)
- QML之使用C++自定义QML类型(三)
- Qt QML 入门 — 使用C++定义QML类型
- QAbstractListModel:Qml 使用C++model
- ObjectModel:Qml 使用C++model
- UIColor的使用及拓展
- objective-c @property 使用
- IOS-1-Objective-C-@property属性的使用及注意问题:@property(assign)int name;
- 使用C++创建新的QML类型
- 在QML中使用自定义属性类型
- QML中使用C++的枚举类型
- QML类型
- 路径规划的MATLAB实现
- Leetcode LRU Cache 解题报告
- Cocos2D-X射击小游戏(十)编码8 游戏流程优化
- python list 操作 增删查
- Python 可视化Facebook用户友谊图
- 使用C++拓展QML 类型及Property binding!
- 点击按钮创建window窗体,窗体重复创建问题
- 第一次开通技术博客
- Test_NOTE
- ubuntu卸载openfire
- 曾经成功企业的失败原因——Leo鉴书70
- Jrtplib的最基本的操作实例
- java 一个简单的程序 夜空中的星
- POJ 1200 Crazy Search(hash).