1.认识附加属性
QML有一个叫附加属性(AttachedProperties)的机制,在QML中默认提供了常用的Keys、Component等附加属性。
如下,我写了个按键的例子 ,因为默认只有获得焦点时才能触发按键事件,代码中我做了转发。
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Row{
spacing: 10
TextField {
width: 60
height: 30
text: "0"
Keys.onUpPressed: {
text=String(Number(text)+1)
}
//forwardTo属性提供了一种将按键,按键释放和来自输入法的键盘输入转发到其他项目的方法。
//当希望一个项目处理某些键(例如,向上和向下箭头键),
//而另一个项目处理其他键(例如,向左和右箭头键)时,此功能很有用。
//一旦已转发密钥的项目接受该事件,它将不再转发给列表中稍后的项目。
Keys.forwardTo: [box] //转发给id-root
}
TextField{
width: 60
height: 30
text: "0"
Keys.onUpPressed: {
text=String(Number(text)+1)
}
}
Rectangle{
id:box
width: 60
height: 30
color: "gray"
Keys.onPressed: {
color=Qt.hsla(Math.random(),1.0,0.5,1.0)
event.accepted=false;
}
}
}
}
那么什么是附加属性?
我们类型设计的时候要考虑单一职责,减少冗余,一些相关但又非必要的属性就可以拿出来作为附加属性。附加属性可以在不破坏类型定义的情况下扩展对象,其功能也可以用动态属性来实现。百度附加属性,主要的结果都是WPF附加属性,我想QML的附加属性应该也是借鉴WPF来的,毕竟作用和写法都类似。
但是既然有了动态属性为什么还要有附加属性?
好吧,我也不知道为啥。除了附加属性比动态属性语法更简洁,两者还有一点点实现上的区别,动态属性是利用元对象机制实现的,新增的属性属于该对象;附加属性是new了一个子节点,新增的属性属于这个子节点。
根据文档说明:
https://doc.qt.io/qt-5/qtqml-syntax-objectattributes.html
Attached properties and attached signal handlers are mechanisms that enable objects to be annotated with extra properties or signal handlers that are otherwise unavailable to the object. In particular, they allow objects to access properties or signals that are specifically relevant to the individual object.
附加属性和附加信号处理程序是允许使用对象不可用的额外属性或信号处理程序来批注对象的机制。特别是,它们允许对象访问与单个对象特别相关的属性或信号。
A QML type implementation may choose to create an attaching type in C++ with particular properties and signals. Instances of this type can then be created and attached to specific objects at run time, allowing those objects to access the properties and signals of the attaching type. These are accessed by prefixing the properties and respective signal handlers with the name of the attaching type.
QML类型的实现可以选择具有特定的属性和信号。然后,可以在运行时创建此类型的实例并将其附加到特定对象,从而允许这些对象访问附加类型的属性和信号。通过在属性和相应的信号处理程序前面加上附加类型的名称来访问这些信号处理程序。
附加属性或处理程序的使用语法如下:
- <AttachingType>.<propertyName>
- <AttachingType>.on<SignalName>
2.实现附加属性
若是使用C++来扩展QML,要想实现一个附加属性的功能,需要两个步骤:
- 提供一个静态函数:static [类型] * qmlAttachedProperties(QObject *); 注意,这个返回类型可以是自身,也可以是关联的类型,参照官方示例attached,当你用 类型.属性 语法的时候只能用返回类型的属性;
- 使用宏声明该类型支持附加属性:QML_DECLARE_TYPEINFO([类型], QML_HAS_ATTACHED_PROPERTIES)
这里借用QtCreator中的示例attached(由于代码较长,我就不贴了,详情见官方示例源码):
这是一个非Ui的小例子,网上也有一些不完全的讲解。首先是BirthdayParty,他提供了静态函数和宏来支持附加属性,而静态函数返回的是BirthdayPartyAttached类型,BirthdayPartyAttached具有rsvp属性。但外单独定义了普通Person、Gril、Boy类并注册为QML类型。
有意思的来了,支持附加属性的类可以直接作为属性出现在对象中,而不是用 Type{ } 这种组件的方式组合起来。
import People 1.0
import QtQuick 2.0 // For QColor
BirthdayParty {
Boy {
name: "Robert Campbell"
BirthdayParty.rsvp: "2009-07-01"
}
Boy {
name: "Leo Hodges"
shoe { size: 10; color: "black"; brand: "Reebok"; price: 59.95 }
BirthdayParty.rsvp: "2009-07-06"
}
host: Boy {
name: "Jack Smith"
shoe { size: 8; color: "blue"; brand: "Puma"; price: 19.95 }
}
}
main.cpp的逻辑也很简单,就是判断/打印qml中那些属性的值,唯一要注意的是他使用了 QObject *attached = qmlAttachedPropertiesObject<BirthdayParty>(guest, false); 来获取组件的附加属性对象。
我们扩展一下示例的附加属性,增加一个新的属性值rsvp2,并在QML中使用,然后打印可以看到附加同一类型不同属性不会重复创建。
Boy {
name: "Leo Hodges"
shoe { size: 10; color: "black"; brand: "Reebok"; price: 59.95 }
BirthdayParty.rsvp: "2009-07-06"
BirthdayParty.rsvp2: "2009-07-06"
}
#include <QObject>
BirthdayPartyAttached *BirthdayParty::qmlAttachedProperties(QObject *object)
{
qDebug()<<"attach"<<object;
return new BirthdayPartyAttached(object);
}
3.参考:
文档:QML Object Attributes | Qt QML 5.15.17