qt quick中qml编程语言
原创文章,转载请注明转自 >> Thuai’s blog
文章链接>> http://www.thuai.com/archives/50
Qt QML 入门 — 使用C++定义QML类型
注册C++类
注册可实例化的类型
如果一个C++类继承自QObject,如果需要在QML中使用创建对象,则需要注册为可实例化的QML类型。
使用qmlRegisterType()注册可实例化的QML类型,具体查看qmlRegisterType()的文档说明。
//Message.cpp
class Message : public QObject
{
Q_OBJECT
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
public:
// ...
};
//main.cpp
#include <QtQml>
...
qmlRegisterType<Message>("com.mycompany.messaging", 1, 0, "Message");
...
//aQmlFile.qml
import com.mycompany.messaging 1.0
Message {
author: "Amelie"
creationDate: new Date()
}
注册不实例化的QML类型
1. qmlRegisterType()不带参数 这种方式无法使用引用注册的类型,所以无法在QML中创建对象。
2. qmlRegisterInterface() 这种方式用于注册C++中的虚基类。
3. qmlRegisterUncreatableType()
4. qmlRegisterSingletonType() 这种方法可以注册一个能够在QML中使用的单例类型。
附带属性
在QML语法中有一个附带属性的概念。
这里使用C++自定义QML类型的时候,也可以定义附带属性。
核心的亮点就是
static <AttachedPropertiesType> *qmlAttachedProperties(QObject *object);
和
QML_DECLARE_TYPEINFO()
中声明 QML_HAS_ATTACHED_PROPERTIES
标志
例如:
//Message.cpp
class Message : public QObject
{
Q_OBJECT
Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
public:
// ...
};
//MessageBoardAttachedType.cpp
class MessageBoardAttachedType : public QObject
{
Q_OBJECT
Q_PROPERTY(bool expired READ expired WRITE expired NOTIFY expiredChanged)
public:
MessageBoardAttachedType(QObject *parent);
bool expired() const;
void setExpired(bool expired);
signals:
void published();
void expiredChanged();
};
//MessageBoard.cpp
class MessageBoard : public QObject
{
Q_OBJECT
public:
static MessageBoard *qmlAttachedProperties(QObject *object)
{
return new MessageBoardAttachedType(object);
}
};
QML_DECLARE_TYPEINFO(MessageBoard, QML_HAS_ATTACHED_PROPERTIES)
//在QML中的使用
Message {
author: "Amelie"
creationDate: new Date()
MessageBoard.expired: creationDate < new Date("January 01, 2015 10:45:00")
MessageBoard.onPublished: console.log("Message by", author, "has been
published!")
}
//main.cpp
...
Message *msg = someMessageInstance();
MessageBoardAttachedType *attached =
qobject_cast<MessageBoardAttachedType*>(qmlAttachedPropertiesObject<MessageBoard>(msg));
qDebug() << "Value of MessageBoard.expired:" << attached->expired();
...
MessageBoard这个类中首先实现了static *qmlAttachedProperties(QObject *object),然后又用QML_DECLARE_TYPEINFO(MessageBoard, QML_HAS_ATTACHED_PROPERTIES)声明MessageBoard为附带属性。
水平有限,还请不吝指正!
文章属原创,转载请注明转自>>[Thuai’s blog][http://www.thuai.com]
Qt QML — QML 和 JavaScript 整合
在QML中使用JavaScript
PRAGAM LIBRARY
C/C++中关键字#pragam,就是指定编译器执行一些特定动作的指令。这里也可以在JavaScript中使用这个关键字,告诉编译器生成一个shared library。
因为在QML component 中如果使用了JavaScript文件,则会每个component都会有 独立的 JavaScript实例 的 copy,但是如果我们不想每个Component都有独立的JavaScript实例呢?这怎么办呢?
这时候就需要在JavaScript文件中使用.pragam library告诉编译器,这个JavaScript文件是可以共享的。
导入JAVASCRIPT
同样也是使用import来导入JavaScript文件到QML文件中使用。
例如:
import "./myJs" as MyJs
这里我使用相对路径来指定js文件,也可以使用绝对路径来指定js文件。为什么这样写呢?其实这就是告诉编译器,需要使用到的qml文件和js文件的目录位置方便引用解析。如此,你可以将QML文件和js文件按照层级关系和不同的作用,分类放置不用放在和main.qml文件同级目录,从而有个清晰的项目文件结构。
在JAVASCRIPT文件中引用其他JAVASCRIPT文件
在QtQuick1.x中是不支持,在js文件中引用另外的非无状态js文件的。
QtQuick2.0版本则支持在一个非无状态的js文件中引用另外一个无状态的js文件或者QML模块。
使用.pragam library定义无状态的JavaScript。
使用.imports则可以导入其他js文件和QML模块。
.import TypeNamespace MajorVersion.MinorVersion as Qualifier
使用Qt.include包含其他非无状态的js文件。文档中有这样一个例子,可以很明了的看出如何使用Qt.include
//main.qml
import QtQuick 2.0
import "script.js" as MyScript
Item {
100; height: 100
MouseArea {
anchors.fill: parent
onClicked: {
MyScript.showCalculations(10)
console.log("Call factorial() from QML:",
MyScript.factorial(10))
}
}
}
// script.js
Qt.include("factorial.js")
function showCalculations(value) {
console.log("Call factorial() from script.js:",
factorial(value));
}
// factorial.js
function factorial(a) {
a = parseInt(a);
if (a <= 0)
return 1;
else
return a * factorial(a - 1);
}
script.js中使用Qt.include来包含factorial.js,而在main.qml文件中只是使用了一个qualifier MyScript就访问了两个js文中定义的function。
使用JavaScript动态创建QML object
动态创建QML object 有两种方式:
-
使用Qt.createComponent()
-
使用Qt.createQmlObject()
如果你自定义了一个QML组件,则使用Qt.createComponent()动态创建对象会方便一些。方便重用自定义component。
可以参看我的这篇Qt QML– 动态创建QML objects和销毁
JavaScript的运行环境
QML引擎提供的JavaScript运行环境和浏览器提供的JavaScript运行环境是不一样的。QML的运行环境实现了”ECMAScript Language Specification”的标准,支持ECMAScript标准的内建类型和函数,如Object,Array,Math等。关于详细的ECMAScript标准有哪些内建类型,可以参看ECMA-262 第5版的文档。
水平有限,还请不吝指正,谢谢!
文章属原创,转载请注明转自>>Thuai’s blog
发表在 Qt、Qt QML | 标签有 QML、Qt | 发表回复
Qt QML — 调试QML程序
使用Console调试
Log
console.log 打印日志信息
console.debug 打印调试信息
console.info 打印普通信息
console.warn 打印警告信息
console.error 打印错误信息
Assert
就像C++就的assert,判断表达式是否成立。QML中的console.assert在表达式不成立时并不会终止程序,而是会打印出错误的代码位置。
console.assert 断言
Timer
console.time 和 console.timeEnd 用来查看代码运行所花费的时间。
Trace
在JavaScript的函数中加入console.trace()就可以跟踪代码的调用过程,但是只能够跟踪最后的10次调用。
Count
console.count 会打印出代码调用的次数
Profile
JavaScript 函数的性能分析, console.profile 开始,console.profileEnd 结束。
Exception
console.exception 打印出错误信息和堆栈调用信息。
包含模块的调试 (Debugging module imports)
添加环境变量QML_IMPORT_TRACE=1,可以查看import的module是否正确。然后在终端中使用qmlscene命令运行指定的qml文件,终端就会输出import信息。
水平有限,还请不吝指正,谢谢!
原创文章,转载请注明转自>>Thuai’s blog
发表在 Qt、Qt QML | 标签有 QML、Qt | 发表回复
Qt Quick 2 — QML类型(QML Types)
- 可视类型
- 可视的实用功能项
- 可视项的生成器
- 可视项的变换
- 获取用户输入
- 文本输入的实用工具项
- 用户输入事件
- 位置
- 状态
- 转变和动画
- 与类型相关的动画
- 底层动画
- 路径动画
- 数据模型
- 视图
- 数据存储
- 图形效果
- 实用方便的类型
- 画布
注意: 末尾写了一个2的,表示QtQuick2中才出现的。对于部分新出现的一些类型,我自己也不怎么熟悉,所以暂时不写中文,免得误人子弟就不好了。以后我会再次更新这篇文章。
可视类型 (visual types)
- Item — QML 基本的试图类型,其他可视类型都是从Item继承来的
- Rectangle — 矩形区域
- Image — 图片
- BorderImage — 边框背景
- AnimatedImage — 播放一张GIF图片
- AnimatedSprite — 播放一系列帧动画 2
- SpriteSequence — 播放一系列帧动画中的部分帧 2
- Text — 显示文本
- Window — 显示一个顶层窗口 2
可视的实用功能项 (Visual Item Utility)
- Accessible — 提供Component的获取性 2
- Gradient — 渐变
- GradientStop — 渐变阈值
- SystemPalette — 系统调色板
- Screen — 获取设备的屏幕宽高横向参数 2
- Sprite — 显示特定的Sprite动画 2
- FontLoader — 字体加载器
可视项的生成器 (Visual Item Generation)
- Repeater — 能够根据model生成多个可视化的项
- Loader — QML component动态加载器
可视项的变换 (Visual Item Transformations)
- Transform — 变形 2
- Scale — 缩放
- Rotation — 旋转
- Translate — 平移
获取用户输入 (User Input)
- MouseArea — 鼠标区域
- Keys — 按键
- KeyNavigation — 导航键 2
- FocusScope — 焦点区域
- Flickable — 橡皮筋区域
- PinchArea — 捏拽区域
- MultiPointTouchArea — 多点触控区域 2
- Drag –拖动区域 2
- DropArea — 掉落区域 2
- TextInput — 文本输入区域
- TextEdit — 文本编辑区域
文本输入的实用工具项 (Text Input Utility)
- IntValidator — 整数校验器
- DoubleValidator — 双精度浮点校验器
- RegExpValidator — 正则表达式校验器
用户输入事件 (User input events)
- TouchPoint — 触摸点击事件 2
- PinchEvent — 捏拽事件
- WheelEvent — 鼠标滚轮事件 2
- MouseEvent — 鼠标点击事件
- KeyEvent — 按键事件
- DragEvent — 拖动事件 2
位置 (Positioning)
- Positioner — Item在scene中的位置信息(附带属性) 2
- Column — 子对象竖直方向排列
- Row — 子对象水平方向排列
- Grid — 子对象按照网格形式排列
- Flow — 流动
- LayoutMirroring — 布局镜像(附带属性) 2
状态 (States)
- State — 状态
- PropertyChanges — 属性变更
- StateGroup — 状态组
- StateChangeScript — 状态变更脚本
- ParentChange — 父对象变更
- AnchorChanges — 锚点变更
转变和动画 (Transitions and Animations)
- Transition — 转变动画
- ViewTransition — 视图转变 2
- SequentialAnimation — 串行动画序列
- ParallelAnimation — 并行动画序列
- Behavior — 特定属性变化时的行为
- PropertyAction — 在动画序列中执行属性变更动作
- SmoothedAnimation — 属性值平滑变化动画
- SpringAnimation — 弹力动画
- ScriptAction — 在动画序列中执行脚本(主要用于动画中执行脚本)
与类型相关的动画 (Type-specific Animations)
- PropertyAnimation — 属性动画
- NumberAniamtion — 数值动画
- Vector3dAnimation — Vector3d属性的动画
- ColorAnimation — color属性的动画
- RotationAnimation — rotation属性的动画
- ParentAnimation — parent属性动画
- AnchorAnimation — anchor属性动画
- PathAnimation — path动画 2
底层动画 (Lower-level Animation Types)
- PathInterpolator — path修改器 2
- AnimationController — 动画控制器 2
路径动画 (Animation paths)
- Path — 路径
- PathLine — 路径为直线
- PathQuad — 路径为二次方程式贝尔曲线
- PathCubic — 路径为三次方程式贝尔曲线
- PathArc — 路径为弧线 2
- PathCurve — 路径为曲线 2
- PathSvg — SVG 路径 2
- PathAttribute — 在path中设置属性
- PathPercent — 修改path中item的间距
数据模型 (Model and Model Data)
- ListModel
- ListElement
- VisualItemModel
- VisualDataModel
- VisualDataGroup
- XmlListModel
- XmlRole
视图 (Views)
- ListView
- GridView
- PathView
- Pack age
数据存储 (Data Storage)
- QtQuick.LocalStorage 2 — 本地存储模块 2
图形效果 (Graphical Effects)
- Flipable
- ShaderEffect 2
- ShaderEffectSource
- GridMesh 2
- QtQuick.Particles 2 2
实用方便的类型 (Convenience Types)
- Connections
- Binding — 绑定器
- Timer — 定时器
- WorkScript
画布 (Canvas)
- Canvas 2
- Context2D 2
- CanvasGradient 2
- CanvasPixelArray 2
- CanvasImageData 2
- TextMetrics 2
水平有限,还请不吝指正,谢谢!
原创文章,转载请注明 >> Thuai’s blog
发表在 Qt、Qt QML、Qt Quick | 标签有 QML | 发表回复
Qt QML– 动态创建QML objects和销毁
动态创建Qml对象
使用JavaScript动态创建Qml对象有两种方式,一是使用Qt.createComponent,二是使用Qt.createQmlObject
如果你已经有一个qml文件定义了一个component,则使用Qt.createComponent()这种方式会比较好。如果本身对象就是在Qml运行期生成的对象且简单,则使用Qt.createQmlObject(),你肯定不想在一条语句中写上百来行代码定义一个component对吧!
QT.CREATECOMPONENT
先看代码
//Sprite.qml
import QtQuick 2.0
Rectangle { 80; height: 50; color: "red" }
//main.qml
import QtQuick 2.0
import "componentCreation.js" as MyScript
Rectangle {
id: appWindow
300; height: 300
Component.onCompleted: MyScript.createSpriteObjects();
}
//componentCreation.js
var component;
var sprite;
function createSpriteObjects() {
component = Qt.createComponent("Sprite.qml");
if (component.status == Component.Ready)
finishCreation();
else
component.statusChanged.connect(finishCreation);
}
function finishCreation() {
if (component.status == Component.Ready) {
sprite = component.createObject(appWindow, {"x": 100, "y": 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
} else if (component.status == Component.Error) {
// Error Handling
console.log("Error loading component:", component.errorString());
}
}
从上面的代码看出,先自定义了一个qml文件Sprite.qml,这个qml文件中有个宽80、高50、颜色为红色的Rectangle组件。在main.qml首先是导入了componentCreation.js这个JavaScript脚本,并去了别名MyScript。rootObject则是一个宽300、高300、id为appWindow的Rectangle组件。当这个Rectanle类型的组件加载完成的时候就会调用componentCreation.js中的createSpriteObjects()方法动态创建对象。
核心就是createSpriteObjects()这个方法了。
可以看出使用Qt.createComponet()这种方法动态创建qml对象,需要两个步骤:1.使用Qt.createComponent(url,parent, mode). url即为自定义好的需要创建qml对象的qml文件。parent和mode通常可以不写。具体可以查看文档中Qt.createComponent()的详细说明。因为Qt.createCompoent()成功则会返回一个Component类型的对象,所以需要第二步。2.使用createObject()创建实例,createObject()方法是Component类型的一个方法。createObject()返回的才是Script.qml的实例。
在上面的这段代码中,还可以看到,component.statusChanged这个signal连接了一个createScriptObjects.js中的另外一个方法,通过component.status和Component组件中的不同枚举值对比,进行错误的判断和处理。
总结: Qt.createComponent()这个function是 Qt 这个Qml全局类型中的一个方法,这个方法返回一个Component类型的对象。需要得到自定义qml组件的实例,还需要使用Component.createObject()方法。如果需要使用非阻塞方式创建qml object则可以使用incubateObject()方法。
QT.CREATEQMLOBJECT()
如果需要在qml运行期创建一个qml对象且这个对象定义并不复杂时,则使用Qt.createQmlObject()这种方法比较好。
import QtQuick 2.0
Rectangle {
id: rect
360
height: 360
Text {
anchors.centerIn: parent
text: "Hello World"
}
MouseArea {
anchors.fill: parent
onClicked: {
createObject();
}
}
function createObject()
{
//第一种写法
/*
var object = Qt.createQmlObject('import QtQuick 2.0;' +
'Rectangle {' +
'30; ' +
'height:30;' +
'colo: "red"}', rect, "error");
*/
//第二种写法
//var newObject = Qt.createQmlObject('import QtQuick 2.0; ' + 'Rectangle { 20; height: 20; colo: "red"}', rect, "dynamicSnippet1");
//第三种写法
var newObject = Qt.createQmlObject('import QtQuick 2.0;
Rectangle { 20; height: 20; colo: "red"}', rect, "error3");
}
}
从上面的代码可以看出Qt.createQmlObject()有三个参数,第一个为定义qml对象的字符串。第二个为创建的qml对象的父对象。第三个则为出错时候的文件路径提示。并且提示会出现行数和列数,可以分别试验三种写法看错误提示有何不同。
维护动态创建的Qml对象
动态创建Qml对象,你必须知道它所存在的context的生命周期,必须保证context的生命周期比动态创建的Qml对象生命周期要长,因为context销毁了,其中绑定的动态创建的Qml对象也会失效。动态创建的Qml对象的context取决于它创建的方式。
-
Qt.createComponet(),使用这种方法,则context就是调用这个Qt.createComponent方法的QQmlContext。QQmlContext跟Qt4.8.x中的QDecalartiveContext()其实差不多。
-
Qt.createQmlObject(),使用这种方法,则context就是这个方法的的parent参数。
-
如果使用Component{}定义一个对象,然后在这个Component对象中调用createObject()或者incubateObject()方法,这时动态创建出的对象的context就是这个Component的context。
动态销毁对象
使用Object.destroy()方法删除对象。
在多数情况下,你可以使用改变可视对象的opacity值为0或者将它移出屏幕就可以了,而不是delete它。如果你有很多动态创建的对象,delete那些不用的对象,则是值得做的事情。
记住,不要去删除不是你手动创建的对象,例如Repeater和Loader创建的对象。
例如下面这段代码中SelfDestroyingRect就不能使用destroy来销毁它。
Item {
SelfDestroyingRect {
// ...
}
}
水平有限,还请不吝指正,谢谢!
文章属原创,转载请注明转自>>Thuai’s blog
Qt QML—QML signal与signal handler系统
QML 的signal 和 signal handler机制的存在,是为了应用能够和UI组件之间相互交互。signal就是button clicked、mouse area pressed这些event,signal handler则就是这些事件的响应。
当一个signal emitted,相应的signal handler就会被调用,在signal handler中执行一些scripts或是其他操作,已完成event的响应。
signal和signal handler的定义
signal
signal <signalName>[([<type> <parameter name>[, ...]])]
signal handler
on<SignaleName>
可以参考另一篇文章 Qt QML入门– QML 语法 (2)
Property Change Signal Handler
当Property的值改变了,就会自动emitted一个signal,这种property changed signal,有property Signal handler与之对应。你只需要实现signal handler即可。
on<PropertyName>Changed
使用Connections Type
很多人都知道Qt一个很好的东西,就是signal和slot机制。你可以很方便的connect的signal和slot。QML中的Connections,它能够让你接收指定object的任意signal,从而能够在signal声明的那个Object之外接收到声明的signal,从而实现自己想要logic。
import QtQuick 2.0
Rectangle {
id: rect
100; height: 100
MouseArea {
id: mouseArea
anchors.fill: parent
}
Connections {
target: mouseArea
onClicked: {
rect.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1);
}
}
}
上面的代码中,Connections中的target绑定的是ouseArea,从而在rect中能够接收到mouseArea的signal,如clicked、pressed、released等等signal。
附带的signal handler
附带的signal handler是附带组件的signal与之对应的signal handler,并不是使用附带组件本身Object的signal的signal handler。
可以参看另一篇文章 Qt QML入门– QML 语法 (2)
signal与signal的连接,signal与method的连接
signal 都有一个connect()方法,可以连接method或者signal。
可以看下面两段代码
signal connect signal
Rectangle {
id: forwarder
100; height: 100
signal send()
onSend: console.log("Send clicked")
MouseArea {
id: mousearea
anchors.fill: parent
onClicked: console.log("MouseArea clicked")
}
Component.onCompleted: {
mousearea.clicked.connect(send)
}
}
注意:mousearea.clicked.connect(send),这里send是signal但是却没有加或括号。emitted signal的时候则不论是否signal声明的时候有无括号,都须要加上括号。
signal connect method
Rectangle {
id: relay
signal messageReceived(string person, string notice)
Component.onCompleted: {
relay.messageReceived.connect(sendToPost)
relay.messageReceived.connect(sendToTelegraph)
relay.messageReceived.connect(sendToEmail)
}
function sendToPost(person, notice) {
console.log("Sending to post: " + person + ", " + notice)
}
function sendToTelegraph(person, notice) {
console.log("Sending to telegraph: " + person + ", " + notice)
}
function sendToEmail(person, notice) {
console.log("Sending to email: " + person + ", " + notice)
}
}
注意:这里使用connect连接是的method,同样没有加上括号。
既然能够connect,那有没有disconnect呢?当然有。
有时候,你不使用disconnect,你某些动态create的对象都无法distroy。
Rectangle {
id: relay
//...
function removeTelegraphSignal() {
relay.messageReceived.disconnect(sendToTelegraph)
}
}
disconnect跟connect就只是一个单词差别而已,没有其他特别不同的地方。
水平有限,还请不吝指正,谢谢!
原创文章,转载请注明 >> Thuai’s blog
Qt QML—QML 属性的绑定(Property Binding)
QML 属性绑定 (Property Binding)
属性的绑定能够更好的使用QML的特性-QML object动态行为变化的自动响应。这是QML一个很重要的特性。
注意:绑定的一个很重要的标志就是“:”–冒号
当QML object 的属性既可以分配一个static value,也可以绑定一个JavaScript表达式,也可以使用JavaScript的自带的Date Math这些对象。因为QML uses a standards compliant JavaScript engine。
Rectangle {
id: parentRect
200; height: 200
Rectangle {
id: childRect
100; height: parent.height
color: "blue"
}
}
上面的代码中,childRect的height绑定到了parent的height,当parentRect的height改变的时候,QML engine会重新计算childRect.height
import QtQuick 2.0
Rectangle {
100
height: width * 2
focus: true
Keys.onSpacePressed: {
height = width * 3
}
}
在看上面的这段代码,Rectangle的height首先绑定了width2,然后在Key.onSpacePressed这个附带的signal handler中,height 被赋值width3,注意是赋值,不是绑定。
所以之前的bind被这个赋值语句移除了,也就是说以后Rectangle的width变化了,height不会自动变成width的2倍。
如果是想要重新binding而不是赋值,则需要使用Qt.binding()。
this的使用
使用JavaScript绑定时,QML允许使用Javascript中this关键字。
例如下面的代码:
Item {
500
height: 500
Rectangle {
id: rect
100
color: "yellow"
}
Component.onCompleted: {
rect.height = Qt.binding(function() { return this.width * 2 })
console.log("rect.height = " + rect.height) // prints 200, not 1000
}
}
rect.heigth属性的绑定使用了JavaScript的语句,所以可以使用this,这里的this表示的是Item而不是rect
水平有限,还请不吝指正,谢谢!
原创文章,转载请注明 >> Thuai’s blog
Qt QML入门– QML 语法 (2)
QML 对象的属性
一个QML对象所具有的属性有以下几种:
- id -id 标识
- property attributes –属性(其中包括继承自Item的attributes,自定义的attributes)
- signal attributes –信号
- signal handler attributes –信号处理
- method attributes –函数
- attached propeties and attached signal handler attributes –附带的属性 和 附带的signal handler
id
id 用来标识QML对象,id不能够以大写字母开头,同样method也不能够以大写字母开头。请记住这点,不然就会有“xxx cannot begin with an upper case letter”这样的error。 有了id你就能够通过id引用id为xxx的对象了。所以尽量的给你的每个QML object都写上id吧! QML object 一旦实例化,id值就无法改变。
Property Attributes
自定义属性的语法格式:
[default] property <propertyType> <propertyName>
例如:
property int myAge 25;
default property string myName thuai
//MyCustomRectangle.qml
property MyCustomRectangle myCusRect
property color myFavoriteColor: "blue"
default关键字表示,该QML object有个默认属性,你使用这个属性的时候不需要显式的声明。
例如:
// MyLabel.qml
import QtQuick 2.0
Text {
default property var someText
text: "Hello, " + someText.text
}
上面的MyLabel类型中中有个default属性someText,所以在MyLable使用的时候,
MyLabel {
Text { text: "world!" }
}
//和这段代码是等效的
MyLable {
someText: Text { text: "world!" }
}
这就是default property
单行语句的分号是可写不用写的。但是一行写多条语句,语句则必须要用分号分隔!
propertyType 可以是QML的基本类型,一种QML对象类型,也可以是QML可以是C++通过Q_PROPERTY宏注册的类,还可以是JavaScript中的var,var它可以表示任何类型的数据,还可以是自定义的QML类型,如MyCustomRectangle
为PROPERTY ATTRIBUTES赋值
-
一是初始化的时候赋值
import QtQuick 2.0 Item{ x: 10 y: 10 100 height: 100 }
-
一是使用的时候赋值。
import QtQuick 2.0 Rectangle { id: rect Component.OnCompleted: { rect.color = “blue” } }
属性组(GROUPED PROPERTIES)
将相同的属性写成一句代码 例如:
Text {
//dot notation
font.pixelSize: 12
font.b: true
}
Text {
//group notation
font { pixelSize: 12; b: true }
}
font.pixelSize 和 font.blod用括号括起来写成了一句,注意 pixelSize和 b之间有个;
属性别名(PROPERTY ALIASES)
格式: [default] property alias <name>: <alias reference>
// Button.qml
import QtQuick 2.0
Rectangle {
property alias buttonText: textItem.text
100; height: 30; color: "yellow"
Text { id: textItem }
}
Button中的属性buttonText是textItem.text属性的别名
Button { buttonText: "Click Me" }
所以对Button的buttonText属性赋值就相当于给Text的text属性赋值
注意: Property Aliases 必须在组件所有初始化工作都完成之后,才能够使用,否则会出错。
import QtQuick 2.0
Rectangle {
360
height: 360
property alias aText: te
//error before Rectangle initialized completed
//aText: "init text"
Component.onCompleted: {
aText.text = "init text onCompleted"
}
Text {
id: te
anchors.centerIn: parent
}
}
如果你在component初始化完成,对alias properties赋初始值,QtCreator会报“Cannot assign to non-existent property “aText”错误!
这里又看到了一个有意思的东西。Component.onCompleted,这是一个QtQuick所有的Object都有的一个附带信号处理函数。组件初始化创建完成就会触发这个处理函数。后面在关于signal的文章中有更详细的讲解。
PROPERTY MODIFIER OBJECTS
<PropertyModifierTypeName> on <propertyName> {
// attributes of the object instance
}
这里Property Modifier Objects我没有用中文,因为我也不知道该译成什么。具体后面的例子中大家可以看到Property Modifier Objects的应用。如下面代码中的NumberAnimation
import QtQuick 2.0
Rectangle {
360
height: 360
Rectangle {
id: moveRect
50
height: 50
radius: 5
color: "red"
NumberAnimation on x {
from: 0
to: 100
duration: 200
}
}
}
信号(Signal Attributes)
信号属性定义语法:
signal <signalName>[([<type> <parameter name>[, ...]])]
[]
表示可选
例如:
//不带参数和括号
signal mySignal
//带空括号
signal mySignal2()
//signal 信号名(参数类型 参数名, 参数a类型 参数a)
signal mySignal3(string name, var any)
对应的signal handler的语法格式则是:
on<SignalName>
如上例中的mySignal,对应的signal handler 就写成 onMySignal
注意: mySignal的第一个字母S成了大写的了。因为这里onMySignal,on作为开头了。所以按照QML的语法,mySignal中的m就要写成M, signal 还可以以下划线_开头, 比如_mySignal4,对应的signal handler则写成on_MySignal4,下划线的数目也可以不同。再比如__mySignal4和_mySignal4**就是两个不同的signal(前者一个下划线,后者两个下划线)
signal mySignal3的 signal handler:
onMySignal3: {
console.debug("i'm a signal handler")
console.debug("name"en);
}
QML有内建的属性signal,当属性的value变化的时候,就会emitted signal. 这个就是文档中所说的Property Changed Signal
import QtQuick 2.0
Item {
100; height: 100
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Click!")
}
}
}
MouseArea有clicked signal, 当鼠标点击MouseArea 的时候,就会emit clicked signal。 signal handler onClicked 就会触发,console 就会打印出“Click!“
Signal Handler是一种特殊的method属性。当你在QML中文件中声明一个singal的时候,QML会自动帮你关联一个signal handler,这个signal handler默认是没有实现的。所以你只需要实现这个signal handler就可以了,然后在emitted一个signal的时候,与之关联的signal handler就会自动的被QML引擎调用。
例如文档中的一个例子:
// SquareButton.qml
Rectangle {
id: root
signal activated(real xPosition, real yPosition)
signal deactivated //注意我没有括号哦!
100; height: 100
MouseArea {
anchors.fill: parent
onPressed: root.activated(mouse.x, mouse.y) //emit activated signal and parameter
onRelased: root.deactivated() //emit deactivated signal 注意我有括号哦!
}
}
// myapplication.qml
SquareButton {
//implement onActivated signal
onActivated: console.log("Activated at " + xPosition + "," + yPosition)
//implement onDeactivated signal
onDeactivated: console.log("Deactivated!")
}
在SquareButton.qml中的MouseArea,pressed、released都emitted了一个signal。 由此可以看出QML中emitted一个signal,你只需要调用它就行了。
注意:在QML中声明无参signal你可以不带括号,但是emitted它的时候,就必须要带括号了。否则,它不会报错,但是它也不会emitted signal
而在Qt C++代码中你要想emittd一个signal,你就必须使用emit <定义的信号>,才能够emit一个signal。
在myapplication.qml中你使用SquareButton这个自定义的Component时,只需实现下onActivated、onDeactivated这两个signal handler就行,因为QML已经帮你declare并connected了。
signal不仅有signal handler,它还可以与后面讲到的method连接(connect),Qt 一个很重要的机制就是信号和槽机制,其实在QML中也有这个,只是叫法不一样而已。QML中所有的method都是slot。
PROPERTY CHANGE SIGNAL HANDLERS
语法格式:
on<Property>Changed
signal 有signal handler,property呢? property有property changed signal handler(属性变化信号处理方法,呵呵有点拗口,翻译水平不行,不纠结在这种意会的层次,能够理解就行),既然也是signal hanlder那就不需要你去declare它并关联到信号了。你也只需要使用它就行了。
例文档中的:
import QtQuick 2.0
TextInput {
text: "Change this!"
onTextChanged: console.log("Text has changed to:", text)
}
方法(Method Attributes)
QML定义一个method:
function <functionName>([<parameterName>[, ...]]){ <body> }
QML中的method定义不像signal的定义,需要声明参数(parameter)的类型(type),QML中method的参数类型是var,也只能是var,不论它是在QML中定义的method还是C++中定义的指定参数的method然后注册到QML system中使用的。
对JavaScript熟悉的朋友,应该知道var这个关键字。(此处可以问歌哥或者度娘,建议歌哥,因为度娘都是copy的相似答案)
这是QML定义method的语法格式,C++中的method,可以用Q_INVOKABLE和 slots注册到QML系统中,这样QML中就可以访问你C++中写的method方法了。具体我会在后面关于C++与QML交互的文章中详细表述。
这里先暂不写JavaScript中的method如何在QML object中访问。先理解QML object定义的method如何正确使用,再拓展其他方法定义的method如何使用。
import QtQuick 2.0
Item {
200; height: 200
MouseArea {
id: msArea
anchors.fill: parent
onClicked: label.moveTo(mouse.x, mouse.y)
}
Text {
id: label
function moveTo(newX, newY) {
label.x = newX;
label.y = newY;
}
text: "Move me!"
}
}
上面的代码中,id为label的Text中有个method moveTo(newX, newY)
更改label的x、y值,从而移动label,当点击Item中的任意一点,Item中MouseArea msArea自动emitted clicked signal, signal handler onClicked 自动调用label.moveTo()。
从这个例子,你应该能够理解了如何定义一个QML method以及如何调用一个QML method。所以我建议我同事都最好每个component都加上id,不要图少敲几个键,而让代码的可读性降低。
附带的属性和附带的信号处理函数 (Attached Properties and Attached Signal Handlers)
定义的语法格式:
<AttachingType>.<propertyName>
<AttachingType>.on<SignalName>
import QtQuick 2.0
ListView {
240; height: 320
model: 3
delegate: Rectangle {
100; height: 30
color: ListView.isCurrentItem ? "red" : "yellow"
}
}
在上面的代码中,isCurrentItem就是ListView的一个附带属性。ListView还有很多附带的属性,详见QtCreator中的帮助。
Component.onCompleted则是一个附带的Signal handler。
水平有限,还请不吝指正!
非常感谢网友lei,为本文勘正
原创文章,转载请注明 >> Thuai’s blog
发表在 Qt、Qt QML | 标签有 QML、Qt | 发表回复
Qt QML入门– QML 语法 (1)
一个qml文件的结构
- 需要包含的模块
- 唯一一个root对象
包含模块
import ModuleIdentifier Version.Number [as <Qualifier>]
例如:
//HelloWorld.qml
import QtQuick 2.0
或者
import QtQuick 2.0 as Quick
详见文档–Import Statements
有且仅有一个ROOT对象
import QtQuick 2.0
Rectangle { 200; height: 200; color: "red" }
Rectangle { 200; height: 200; color: "blue" } // invalid!
这种在一个qml文件中写两个root object是错误的,只能有一个root object,下面的代码就是正确的形式。
import QtQuick 2.0
Rectangle { 200; height: 200; color: "red" }
qml的基本语法
模块的包含
QML 模块的包含,只能使用关键字 import 包含qml文件需要用到模块,import关键字后面的内容可以有三种:
- 注册的带有版本好的模块
- 指定路径的qml文件
- 一个JavaScript文件
例如:
import QtQuick 2.0
import QtQuick.LocalStorage 2.0 as Database
import "../privateComponents"
import "somefile.js" as Script
其中第一种和第二种都是包含带有版本号注册的模块。
对象的声明
Rectangle { 100 height: 100 color: "red" }
上面的代码就使用Rectangle元素声明了一个宽100,高100,颜色为red的对象。
子对象的声明
例1
import QtQuick 2.0
Rectangle {
id: rect
100
height: 100
gradient: Gradient {
id: grad
GradientStop {id: gStopYellow; position: 0.0; color: "yellow" }
GradientStop {id: gStopGreen; position: 1.0; color: "green" }
}
}
例2
import QtQuick 2.0
Rectangle {
id: rect
200
height: 200
color: "red"
Text {
id: text
anchors.centerIn: parent
text: "Hello, QML!"
}
}
上面的两个例子都使用了子对象。这里引出了一个概念
- QML对象树中,的父子关系
- 试图上的父子对象
例1中Rectangle对象rect中的gradient属性中有个子对象grad,grad中又有两个GradientStop子对象。这些父子对象的上下文环境(context)是QML object tree 中的父子对象关系 ,而不是visual scene 上下文环境的父子对象关系。
例2中的Text与Rectangle的父子关系即是object tree中的父子关系也是visual scene中的父子对象关系。
注释
和大多数语言一样,有单行注释// 和 块注释 /* */
=================== End