注册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
...
qmlRegisterType("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 *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(qmlAttachedPropertiesObject(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]
文章链接>>http://www.thuai.com/archives/154
发表在 Qt、Qt QML |
Qt QML — QML 和 JavaScript 整合
发表于 2013 年 2 月 17 日
- 在QML中使用JavaScript
- pragam library
- 导入JavaScript
- 在JavaScript文件中引用其他JavaScript文件
- 使用JavaScript动态创建QML object
- 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 {
width: 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
文章链接>>http://www.thuai.com/archives/118
发表在 Qt、Qt QML | 标签有 QML、Qt |
Qt QML — 调试QML程序
发表于 2013 年 2 月 11 日
- 使用Console调试
- Log
- Assert
- Timer
- Trace
- Count
- Profile
- Exception
- 包含模块的调试
使用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
文章链接>>http://www.thuai.com/archives/123
发表在 Qt、Qt QML | 标签有 QML、Qt |
Ubuntu12.10 中QtCreator无法显示示例的解决方法
发表于 2013 年 2 月 7 日
os版本: Ubuntu12.10_x64 QtCreator版本: 2.6.1 Qt版本:5.0.1
现象:
在打开了QtCreator之后,在欢迎页中示例,无法显示出来,一个也没有。
进入Qt5.0.1的安装目录***\/Qt5.0.1\/5.0.1\/gcc_64\/查看,发现examples目录的权限为700,所属用户为root,所在组为root,而我使用的非root用户登陆的系统,当然在QtCreator由于权限问题,无法访问examples目录了。
解决方法:
更改权限为744即可。
只需要更改权限就可以解决问题了,QtCreator重新启动,在欢迎页中就可以显示所有示例了。
因为我的Qt5.0.1是安装在/opt目录下的,所以运行示例的时候,会提示复制到可写位置。选择一个可写的目录,然后复制打开即可。
水平有限,请不吝指正,谢谢!
文章属原创,转载请注明转自>>Thuai’s blog
文章链接>>http://www.thuai.com/archives/125
发表在 Qt、QtCreator | 标签有 Qt、QtCreator |
Qt Quick 2 — QML类型(QML Types)
发表于 2013 年 2 月 5 日
发表在 Qt、Qt QML、Qt Quick | 标签有 QML |
Qt QML– 动态创建QML objects和销毁
发表于 2013 年 2 月 4 日
-
动态创建Qml对象
- Qt.createComponent
- Qt.createQmlObject
-
维护动态创建的Qml对象
- 动态销毁对象
动态创建Qml对象
使用JavaScript动态创建Qml对象有两种方式,一是使用Qt.createComponent,二是使用Qt.createQmlObject
如果你已经有一个qml文件定义了一个component,则使用Qt.createComponent()这种方式会比较好。如果本身对象就是在Qml运行期生成的对象且简单,则使用Qt.createQmlObject(),你肯定不想在一条语句中写上百来行代码定义一个component对吧!
Qt.createComponent
先看代码
//Sprite.qml
import QtQuick 2.0
Rectangle { width: 80; height: 50; color: "red" }
//main.qml
import QtQuick 2.0
import "componentCreation.js" as MyScript
Rectangle {
id: appWindow
width: 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
width: 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 {' +
'width:30; ' +
'height:30;' +
'colo: "red"}', rect, "error");
*/
//第二种写法
//var newObject = Qt.createQmlObject('import QtQuick 2.0; ' + 'Rectangle { width: 20; height: 20; colo: "red"}', rect, "dynamicSnippet1");
//第三种写法
var newObject = Qt.createQmlObject('import QtQuick 2.0; \n Rectangle {width: 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
文章链接>>http://www.thuai.com/archives/119
发表在 Qt、Qt QML |
Qt QML—QML signal与signal handler系统
发表于 2013 年 2 月 4 日
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 [([ [, ...]])]
signal handler
on
可以参考另一篇文章 Qt QML入门– QML 语法 (2)
Property Change Signal Handler
当Property的值改变了,就会自动emitted一个signal,这种property changed signal,有property Signal handler与之对应。你只需要实现signal handler即可。
onChanged
使用Connections Type
很多人都知道Qt一个很好的东西,就是signal和slot机制。你可以很方便的connect的signal和slot。QML中的Connections,它能够让你接收指定object的任意signal,从而能够在signal声明的那个Object之外接收到声明的signal,从而实现自己想要logic。
import QtQuick 2.0
Rectangle {
id: rect
width: 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
width: 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
文章链接 >>http://www.thuai.com/archives/116
发表在 Qt、Qt QML |
Qt QML—QML 属性的绑定(Property Binding)
发表于 2013 年 2 月 4 日
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
width: 200; height: 200
Rectangle {
id: childRect
width: 100; height: parent.height
color: "blue"
}
}
上面的代码中,childRect的height绑定到了parent的height,当parentRect的height改变的时候,QML engine会重新计算childRect.height
import QtQuick 2.0
Rectangle {
width: 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 {
width: 500
height: 500
Rectangle {
id: rect
width: 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
文章链接 >>http://www.thuai.com/archives/115
发表在 Qt、Qt QML |
Qt QML入门– QML 语法 (2)
发表于 2013 年 2 月 3 日
- QML 对象的属性
- id
- Property Attributes
- 为Property Attributes赋值
- 属性组
- 属性别名
- Property Modifier Objects
- 信号
- Property Change Signal Handlers
- 方法
- 附带的属性和附带的信号处理函数
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
例如:
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赋值
属性组(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 :
// Button.qml
import QtQuick 2.0
Rectangle {
property alias buttonText: textItem.text
width: 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 {
width: 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
on {
// attributes of the object instance
}
这里Property Modifier Objects我没有用中文,因为我也不知道该译成什么。具体后面的例子中大家可以看到Property Modifier Objects的应用。如下面代码中的NumberAnimation
import QtQuick 2.0
Rectangle {
width: 360
height: 360
Rectangle {
id: moveRect
width: 50
height: 50
radius: 5
color: "red"
NumberAnimation on x {
from: 0
to: 100
duration: 200
}
}
}
信号(Signal Attributes)
信号属性定义语法:
signal [([ [, ...]])]
[]
表示可选
例如:
//不带参数和括号
signal mySignal
//带空括号
signal mySignal2()
//signal 信号名(参数类型 参数名, 参数a类型 参数a)
signal mySignal3(string name, var any)
对应的signal handler的语法格式则是:
on
如上例中的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 {
width: 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 //注意我没有括号哦!
width: 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
语法格式:
onChanged
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 ([[, ...]]){ }
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 {
width: 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)
定义的语法格式:
.
.on
import QtQuick 2.0
ListView {
width: 240; height: 320
model: 3
delegate: Rectangle {
width: 100; height: 30
color: ListView.isCurrentItem ? "red" : "yellow"
}
}
在上面的代码中,isCurrentItem就是ListView的一个附带属性。ListView还有很多附带的属性,详见QtCreator中的帮助。
Component.onCompleted则是一个附带的Signal handler。
点击打开原文链接