QML对象属性
每种QML对象类型都有一个定义好的属性集。每种对象类型的每个实例都是在定义了那个对象类型的属性集的情况下创建的。以下是可以指定的几种不同类型的属性,具体描述如下。
对象声明中的属性
在QML文档中的对象声明定义了一个新的类型。它还声明了一个对象层次结构,如果新定义类型的实例被创建,则将实例化该层次结构。
QML对象类型属性类型集如下所示
- id属性
- 属性属性
- 信号属性
- 信号处理程序属性
- 方法属性
- 附加属性和附加信号处理程序属性
- 枚举属性
以下将详细介绍这些属性。
id属性
每种QML对象类型恰好有一个id属性。该属性由语言本身提供,不能被任何QML对象类型重新定义或覆盖。
可以为对象实例的id属性分配一个值,以便该对象可以被其他对象识别和引用。此id必须以下划线或小写字母开头,并且不能包含除字母、数字和下划线以外的字符。
下面是一个TextInput对象和一个Text对象。 TextInput对象的id值被设置为"myTextInput"。 Text对象通过引用myTextInput.text将其text属性设置为与TextInput的text属性相同的值。 现在,这两个元素将显示相同的文本。
import QtQuick Column { width: 200; height: 200 TextInput { id: myTextInput; text: "Hello World" } Text { text: myTextInput.text } }
可以从声明其的组件作用域内的任何位置引用对象。 因此,id值必须在组件作用域内始终是唯一的。 有关更多信息,请参阅作用域和命名解析。
一旦创建了对象实例,其id属性的值就不能更改。 虽然它可能看起来像普通的属性,但id属性不是普通的属性属性,并且对其具有特殊语义;例如,在上面的例子中无法访问myTextInput.id。
属性属性
属性是对象的属性,可以是静态值或动态表达式的绑定。属性的值可以被其他对象读取。通常,它也可以被另一个对象修改,除非某个特定的QML类型明确禁止为特定属性执行此操作。
定义属性属性
可以在C++中为某种类型定义属性,方法是为类注册一个Q_PROPERTY,然后将其注册到QML类型系统中。或者,可以在QML文档中对象声明中使用以下语法定义对象类型的自定义属性:
[default] [required] [readonly] property <propertyType> <propertyName>
以这种方式,对象声明可以向外部对象公开特定值或更轻松地维护某些内部状态。
属性名称必须以小写字母开头,只能包含字母、数字和下划线。JavaScript的保留字不是有效的属性名称。关键字default
、required
和readonly
是可选的,并修改正在声明的属性的语义。有关更多关于它们各自含义的信息,请参阅即将到来的关于默认属性、必需属性和只读属性的章节。
声明自定义属性隐式创建了一个名为on<PropertyName>Changed的属性值的值更改信号和相关的信号处理程序,其中<PropertyName>是属性的名称,第一个字母大写。
例如,以下对象声明定义了一个从矩形基类型派生的新类型。它有两个新的属性,为其中一个新属性实现了信号处理程序。
Rectangle { property color previousColor property color nextColor onNextColorChanged: console.log("The next color will be: " + nextColor.toString()) }
自定义属性定义中的有效类型
除了枚举类型之外的任何QML值类型都可以用作自定义属性类型。例如,以下都是有效的属性声明:
(枚举值是简单的整数值,可以用int类型来引用。)
某些值类型是由QtQuick模块提供的,因此除非导入该模块,否则不能用作属性类型。请参阅QML值类型文档以获取更多详细信息。
注意,var值类型是一个通用的占位符类型,可以持有任何类型的值,包括列表和对象。
property var someNumber: 1.5 property var someString: "abc" property var someBool: true property var someList: [1, 2, "three", "four"] property var someObject: Rectangle { width: 100; height: 100; color: "red" }
此外,任何QML对象类型都可以用作属性类型。例如:
property Item someItem property Rectangle someRectangle
这同样适用于自定义QML类型。如果QML类型在名为ColorfulButton.qml的文件(在随后被客户端导入的目录中)中定义,那么类型为ColorfulButton的属性也是有效的。
向属性属性赋值
对象实例属性的值可以用两种方式之一指定
- 初始化时的值赋
- 强制值赋
在任一情况下,值可以是静态值或绑定表达式值。
初始化时的值赋值
在初始化时为属性赋值的基本语法是
<propertyName> : <value>
如果需要,初始化值赋值可以与对象声明中的属性定义结合起来。在这种情况下,属性定义的语法变为
[default] property <propertyType> <propertyName> : <value>
以下是一个属性值初始化的示例
import QtQuick Rectangle { color: "red" property color nextColor: "blue" // combined property declaration and initialization }
命令式值赋值
命令式值赋值是指从命令式JavaScript代码中将属性值(静态值或绑定表达式)赋给属性。命令式值赋值的语法与JavaScript赋值运算符相同,如下所示
[<objectId>.]<propertyName> = value
以下是一个命令式值赋值的示例
import QtQuick Rectangle { id: rect Component.onCompleted: { rect.color = "red" } }
静态值和绑定表达式值
如前所述,可能分配给属性有两种类型的值:静态值,和绑定表达式值。后者也被称为属性绑定。
种类 | 语义 |
---|---|
静态值 | 一个不依赖于其他属性的常量值。 |
绑定表达式 | 一个JavaScript表达式,描述一个属性与其他属性的关系。该表达式中的变量称为属性的依赖项。 QML引擎强制执行属性及其依赖项之间的关系。当依赖项的任何值发生变化时,QML引擎会自动重新评估绑定表达式,并将新结果赋给属性。 |
以下是一个同时将这两种类型的值赋给属性的示例
import QtQuick Rectangle { // both of these are static value assignments on initialization width: 400 height: 200 Rectangle { // both of these are binding expression value assignments on initialization width: parent.width / 2 height: parent.height } }
注意:要命令式地分配绑定表达式,绑定表达式必须包含在一个函数中,该函数传递给Qt.binding(),然后必须将Qt.binding()返回的值赋给属性。相比之下,在初始化时分配绑定表达式时不能使用Qt.binding()。有关更多信息,请参见属性绑定。
类型安全性
属性是类型安全的。属性只能分配与属性类型匹配的值。
例如,如果属性是实数,并且尝试将字符串分配给它,将会出现错误
property int volume: "four" // generates an error; the property's object will not be loaded
同样,如果在运行时将错误的类型值分配给属性,新值将不会被分配,并生成错误。
某些属性类型没有自然的价值表示,对于这些属性类型,QML引擎会自动执行字符串到值的类型转换。因此,例如,即使颜色类型的属性存储颜色而不仅仅是字符串,您仍然可以将字符串"red"
分配给颜色属性,而不会报告错误。
请参阅QML值类型以获取支持的属性类型列表。此外,任何可用的QML对象类型也可以用作属性类型。
特殊属性类型
对象列表属性属性
类型为列表的属性可以分配一个包含QML对象类型值的列表。定义对象列表值的语法是括号内的逗号分隔列表
[ <item 1>, <item 2>, ... ]
例如,Item 类型有一个 states 属性,用于存储一组 State 类型对象。下面的代码初始化这个属性的值为三个 State 对象组成的列表。
import QtQuick Item { states: [ State { name: "loading" }, State { name: "running" }, State { name: "stopped" } ] }
如果列表中只有一个项目,方括号可以省略。
import QtQuick Item { states: State { name: "running" } }
在对象声明中,可以使用以下语法指定 list 类型属性:
[default] property list<<ObjectType>> propertyName
与其他属性声明一样,属性初始化可以与属性声明合并,使用以下语法:
[default] property list<<ObjectType>> propertyName: <value>
以下是一个列表属性声明的示例。
import QtQuick Rectangle { // declaration without initialization property list<Rectangle> siblingRects // declaration with initialization property list<Rectangle> childRects: [ Rectangle { color: "red" }, Rectangle { color: "blue"} ] }
如果您希望声明一个属性来存储列表值,这些值不一定是以 QML 对象类型值,应该声明一个 var 属性。
分组属性
在某些情况下,属性包含逻辑分组的一系列子属性。这些子属性可以使用点符号或分组符号进行赋值。
例如,Text 类型有一个 font 分组属性。下面,第一个 Text 对象使用点符号初始化其 font
值,而第二个使用分组符号。
Text { //dot notation font.pixelSize: 12 font.b: true } Text { //group notation font { pixelSize: 12; b: true } }
分组属性类型是具有子属性的属性类型。如果分组属性类型是对象类型(与值类型相对),则包含它的属性必须是只读的。这是为了防止您替换子属性所属的对象。
属性别名
属性别名是持有另一个属性引用的属性。与一个普通的属性定义不同,它为属性分配一个新、唯一的存储空间,属性别名将新声明的属性(称为别名属性)作为直接引用连接到现有属性(被别名的属性)。
属性别名声明看起来像一个普通的属性定义,但是它需要用 alias
关键字而不是属性类型,并且属性声明右侧必须是一个有效的别名引用。
[default] property alias <name>: <alias reference>
与普通属性不同,别名有以下限制:
- 它只能引用别名声明的 type 范围内的对象或对象的属性。
- 它不能包含任意 JavaScript 表达式。
- 它不能引用其类型范围之外声明的对象。
- 别名引用 是必需的,与普通属性的可选默认值不同;别名引用必须在新声明别名时提供。
- 它不能引用 附加属性。
- 它不能引用层级深度为 3 或更大的属性。以下代码将无法工作
property alias color: myItem.myRect.border.color Item { id: myItem property Rectangle myRect }
但是,到深度两层的属性别名将有效。
property alias color: rectangle.border.color Rectangle { id: rectangle }
例如,以下是一个具有 buttonText
别名属性 Button
类型,该属性连接到 Text 子元素的 text
对象
// Button.qml import QtQuick Rectangle { property alias buttonText: textItem.text width: 100; height: 30; color: "yellow" Text { id: textItem } }
以下代码将为子元素 Text 对象创建一个具有定义文本字符串的 Button
。
Button { buttonText: "Click Me" }
在这里,直接修改buttonText
将直接修改textItem.text的值;它不会更改其他值然后更新textItem.text。如果buttonText
不是一个别名,改变它的值实际上不会改变显示的文本,因为属性绑定不是双向的:如果textItem.text被更改,buttonText
的值会发生变化,但反过来不一定。
关于属性别名的注意事项
属性别名可以与现有属性具有相同的名称,实际上覆盖了现有属性。例如,以下QML类型有一个与内置的Rectangle::color属性同名且具有相同名称的color
别名属性
Rectangle { id: coloredrectangle property alias color: bluerectangle.color color: "red" Rectangle { id: bluerectangle color: "#1234ff" } Component.onCompleted: { console.log (coloredrectangle.color) //prints "#1234ff" setInternalColor() console.log (coloredrectangle.color) //prints "#111111" coloredrectangle.color = "#884646" console.log (coloredrectangle.color) //prints #884646 } //internal function that has access to internal properties function setInternalColor() { color = "#111111" } }
使用此类型并引用其color
属性的对象将引用别名而不是常规的Rectangle::color属性。然而,在内部,矩形可以正确设置其color
属性并引用实际定义的属性而不是别名。
属性别名和类型
属性别名不能有显式的类型指定。属性别名的类型是其引用的属性或对象的声明类型。因此,如果您创建了通过id引用的对象的别名并声明了额外的属性,这些额外属性将无法通过别名访问
// MyItem.qml Item { property alias inner: innerItem Item { id: innerItem property int extraProperty } }
由于inner仅是一个Item,您无法从组件外部初始化inner.extraProperty
// main.qml MyItem { inner.extraProperty: 5 // fails }
但是,如果您将inner对象提取到具有专用.qml文件的单独组件中,则可以实例化该组件,并通过别名访问其所有属性
// MainItem.qml Item { // Now you can access inner.extraProperty, as inner is now an ExtraItem property alias inner: innerItem ExtraItem { id: innerItem } } // ExtraItem.qml Item { property int extraProperty }
默认属性
对象定义可以有一个单独的默认属性。默认属性是在没有将值作为特定属性的值显式声明的情况下声明对象时的值所分配的属性。
使用可选的default
关键字声明属性将其标记为默认属性。例如,假设有一个包含默认属性someText
的MyLabel.qml文件
// MyLabel.qml import QtQuick Text { default property var someText text: `Hello, ${someText.text}` }
someText
的值可以在MyLabel
对象定义中分配,如下所示
MyLabel { Text { text: "world!" } }
这具有与以下相同的效果
MyLabel { someText: Text { text: "world!" } }
但是,由于someText
属性已被标记为默认属性,因此不需要显式将Text对象分配给此属性。
您会注意到,可以像添加到任何基Item类型的子对象而无需显式添加到children属性一样将子对象添加到任何地方。这是因为Item的默认属性是其data
属性,并为Item添加到该列表的任何项目自动添加到其children列表中。
默认属性可以用于重新分配项的子项。例如
通过将默认属性alias
设置为inner.children
,将对象作为外部项的子项分配将自动重新分配为内部项的子项。
警告:可以隐式或显式地设置元素的默认列表属性值。在单个元素的定义中,这些两种方法不得混合使用,否则会导致列表中元素的无定义顺序。
Item { // Use either implicit or explicit assignement to the default list property but not both! Rectangle { width: 40 } // implicit data: [ Rectangle { width: 100 } ] // explicit }
必选属性
对象声明可以运用required
关键字将一个属性定义为必填属性。其语法是:
required property <propertyType> <propertyName>
如名称所示,必填属性必须在与对象实例化时设置。违反此规则,如果可以静态检测到,将导致QML应用无法启动。在对动态实例化的QML组件(例如,通过Qt.createComponent)())的调用中违反此规则会引发警告并返回空值。
可以使用以下方式使现有属性成为必填属性:
required <propertyName>
以下示例演示了如何创建一个自定义的Rectangle组件,其中颜色属性必须始终指定。
// ColorRectangle.qml Rectangle { required color }
注意: 您无法从QML中将初始值分配给必填属性,因为这将直接违反必填属性的使用意图。
必填属性在模型-视图-代理代码中起着特殊的作用:如果视图的代理有重命名为与视图的模型、带来的名称匹配的必填属性,则将这些属性将使用与模型的相应值初始化。更多信息,请访问Qt Quick中的模型和视图页面。
有关从C++初始化必填属性的方法,请参阅QQmlComponent::createWithInitialProperties、QQmlApplicationEngine::setInitialProperties 和 QQuickView::setInitialProperties。
只读属性
对象声明可以运用readonly
关键字将一个属性定义为只读属性,语法如下:
readonly property <propertyType> <propertyName> : <value>
只读属性在初始化时必须被分配一个静态值或绑定表达式。一旦设置只读属性,就无法再改变其静态值或绑定表达式。
以下代码中的Component.onCompleted
块是不有效的
Item { readonly property int someNumber: 10 Component.onCompleted: someNumber = 20 // TypeError: Cannot assign to read-only property }
注意: 只读属性不能也作为默认属性。
属性修饰对象
属性可以与属性值修饰对象相关联。以下语法表示与特定属性相关联的属性修饰类型的实例声明:
<PropertyModifierTypeName> on <propertyName> { // attributes of the object instance }
这通常被称为"on"语法。
重要的是要注意到,上述语法实际上是一个对象声明,该声明将实例化一个作用于现有属性的对象。
某些属性修饰类型可能仅适用于特定属性类型,但这并不由语言强制执行。例如,由QtQuick
提供的NumberAnimation
类型将仅用于数值类型(如int
或real
)属性。如果尝试将NumberAnimation
与非数值属性一同使用,将不会产生错误,但该非数值属性将不会被动画化。属性修饰类型与特定属性类型关联时的行为由其实现定义。
信号属性
信号是从对象发出的通知,表明某些事件已经发生:例如,属性已更改,动画已开始或停止,或图像已下载。例如,MouseArea类型具有clicked信号,当用户在鼠标区域内点击时,该信号被发出。
对象可以通过信号处理程序通知,只要发出特定的信号。信号处理程序的语法为on
例如,下面的onClicked信号处理程序声明在MouseArea对象定义中,当点击MouseArea时调用,会导致在控制台打印信息
import QtQuick Item { width: 100; height: 100 MouseArea { anchors.fill: parent onClicked: { console.log("Click!") } } }
定义信号属性
a信号可以通过在C++中对一个类的Q_SIGNAL进行注册来定义该类型,然后将其注册到QML类型系统中。或者,可以在QML文档的对象声明中定义对象类型的自定义信号,语法如下
signal <signalName>[([<parameterName>: <parameterType>[, ...]])]
在同一类型块中尝试声明两个同名信号或方法被视为错误。但是,新的信号可以重用现有信号的名字。(这样做应该小心,因为现有的信号可能会被隐藏,变得不可访问。)
以下是三个信号声明的例子
import QtQuick Item { signal clicked signal hovered() signal actionPerformed(action: string, actionResult: int) }
您还可以以属性样式语法指定信号参数
signal actionCanceled(string action)
为了与方法声明保持一致,应该优先使用冒号进行类型声明。
如果没有参数,括号“()”是可选的。如果使用参数,参数类型必须声明,例如在上面的actionPerformed
信号中的string
和int
参数。允许的参数类型与定义属性属性页面上列出的类型相同。
要发出信号,将其作为方法调用。任何相关的信号处理程序将在信号发出时被调用,并且处理程序可以使用定义的信号参数名来访问对应的参数。
属性更改信号
QML类型还提供内置的属性更改信号,当属性值更改时发出,这在属性属性部分中已描述。请参阅即将到来的有关属性更改信号处理程序的部分,了解更多关于这些信号为何有用以及如何使用它们的信息。
信号处理程序属性
信号处理程序是一种特殊的方法属性,其中方法实现由QML引擎在关联信号发出时调用。在QML对象定义中添加信号将自动将关联的信号处理程序添加到定义中,默认情况下该处理程序为空实现。客户端可以提供实现,以实现程序逻辑。
考虑以下SquareButton
类型,其定义在下面的SquareButton.qml
文件中,如下所示,包含了信号activated
和deactivated
// SquareButton.qml Rectangle { id: root signal activated(xPosition: real, yPosition: real) signal deactivated property int side: 100 width: side; height: side MouseArea { anchors.fill: parent onReleased: root.deactivated() onPressed: mouse => root.activated(mouse.x, mouse.y) } }
这些信号可以由同一目录中的另一个QML文件中的任何SquareButton
对象接收,其中客户端提供信号处理程序的实现
// myapplication.qml SquareButton { onDeactivated: console.log("Deactivated!") onActivated: (xPosition, yPosition) => { console.log(`Activated at {xPosition}, ${yPosition}`) } }
信号处理程序不需要声明它们的参数类型,因为信号已经指定了它们。上面的箭头函数语法不支持类型注解。
有关使用信号更详细的信息,请参阅信号和处理器事件系统。
属性改变信号处理器
属性改变信号处理器采用以下语法形式 on<属性>Changed,其中 <属性> 是属性名称,首字母大写。例如,虽然 TextInput 类型的文档没有记录 textChanged
信号,但由于 TextInput 具有相应的 text 属性,因此可以编写一个 onTextChanged
信号处理器,当属性发生变化时自动调用。
import QtQuick TextInput { text: "Change this!" onTextChanged: console.log(`Text has changed to: ${text}`) }
方法属性
对象类型的方法是一个可以调用的函数,用于执行某些处理或触发其他事件。可以将方法与信号连接,以便在信号发出时自动调用它。有关详细信息,请参阅 信号和处理事件系统。
定义方法属性
在 C++ 中,可以按以下方式为一个类型定义方法:将类的函数标记为 Q_INVOKABLE 或将它们注册为类的 Q_SLOT。或者,可以使用以下语法在 QML 文档的对象声明中添加一个自定义方法:
function <functionName>([<parameterName>[: <parameterType>][, ...]]) [: <returnType>] { <body> }
可以通过添加方法到 QML 类型来定义独立、可重用的 JavaScript 代码块。这些方法可以从内部或外部对象中调用。
与信号不同,方法参数类型不需要声明,默认为 var
类型。但是,您应该声明它们,以便帮助 qmlcachegen 生成更高效的代码,并提高可维护性。
在同一个类型块中尝试声明两个同名的方法或信号是一个错误。然而,新方法可以重用类型中现有方法的名称(这样做应该谨慎,因为现有方法可能会被隐藏且无法访问)。
以下是具有调用 calculateHeight()
方法的 Rectangle。当分配 height
值时调用此方法。
import QtQuick Rectangle { id: rect function calculateHeight(): real { return rect.width / 2; } width: 100 height: calculateHeight() }
如果方法有参数,它们可以在方法内部通过名称访问。以下示例中,当 MouseArea 被点击时,它调用 moveTo()
方法,然后可以引用接收到的 newX
和 newY
参数以重新定位文本。
import QtQuick Item { width: 200; height: 200 MouseArea { anchors.fill: parent onClicked: mouse => label.moveTo(mouse.x, mouse.y) } Text { id: label function moveTo(newX: real, newY: real) { label.x = newX; label.y = newY; } text: "Move me!" } }
附加属性和附加信号处理器
附加属性 和 附加信号处理器 是使对象能够添加额外的属性或信号处理器的机制,否则这些属性或信号处理器对对象不可用。特别是,它们允许对象访问与特定对象特别相关的属性或信号。
一个 QML 类型实现可以选择在 C++ 中 创建具有特定属性和信号的附加类型。然后可以创建此类型的实例并将其在运行时附加到特定的对象上,使这些对象能够访问附加类型的属性和信号。这些属性和信号通过在属性和相应的信号处理器前加上附加类型的名称来访问。
附加属性和信号处理器的引用采用以下语法形式
<AttachingType>.<propertyName> <AttachingType>.on<SignalName>
例如,ListView 类型有一个附加属性 ListView.isCurrentItem,它在 ListView 中的每个委托对象中都可用。该属性可以被每个委托对象用来判断自己是否是当前选中的项目
import QtQuick ListView { width: 240; height: 320 model: 3 delegate: Rectangle { width: 100; height: 30 color: ListView.isCurrentItem ? "red" : "yellow" } }
在这种情况下,附加类型的名称是 ListView
,相关的属性是 isCurrentItem
,因此附加属性被称为 ListView.isCurrentItem
。
附加信号处理器的引用方式相同。例如,常见的附加信号处理器 Component.onCompleted 通常用于在组件创建过程完成时执行一些JavaScript代码。在下面的示例中,一旦 ListModel 已经完全创建,它的 Component.onCompleted
信号处理器将自动被调用以填充模型
import QtQuick ListView { width: 240; height: 320 model: ListModel { id: listModel Component.onCompleted: { for (let i = 0; i < 10; i++) { append({ Name: `Item ${i}` }) } } } delegate: Text { text: index } }
由于附加类型的名称是 Component
,并且该类型有一个 completed 信号,因此附加信号处理器被称为 Component.onCompleted
。
关于访问附加属性和信号处理器的注意事项
一个常见的错误是假设附加属性和信号处理器可以直接从这些属性附加的对象的子对象中直接访问。情况并非如此。附加类型的实例仅附加到特定的对象,而不是对象及其所有子对象。
例如,下面是前面提到附加属性的修改版示例。这次,委托是 Item,而着色的 Rectangle 是该项目的子对象。
import QtQuick ListView { width: 240; height: 320 model: 3 delegate: Item { width: 100; height: 30 Rectangle { width: 100; height: 30 color: ListView.isCurrentItem ? "red" : "yellow" // WRONG! This won't work. } } }
这并不像预期那样工作,因为 ListView.isCurrentItem
仅附加到根委托对象,而不是其子对象。由于 Rectangle 是委托的子对象,而不是委托本身,因此它不能像 ListView.isCurrentItem
那样访问 isCurrentItem
附加属性。因此,矩形应该通过根委托来访问 isCurrentItem
。
ListView { delegate: Item { id: delegateItem width: 100; height: 30 Rectangle { width: 100; height: 30 color: delegateItem.ListView.isCurrentItem ? "red" : "yellow" // correct } } }
现在 delegateItem.ListView.isCurrentItem
正确地引用了委托的 isCurrentItem
附加属性。
枚举属性
枚举提供了一组命名的固定选择。它们可以在QML中使用 enum
关键字声明。
// MyText.qml Text { enum TextType { Normal, Heading } }
如上所示,枚举类型(例如 TextType
)和值(例如 Normal
)必须以大写字母开头。
值通过 <Type>.<EnumerationType>.<Value>
或 <Type>.<Value>
进行引用。
// MyText.qml Text { enum TextType { Normal, Heading } property int textType: MyText.TextType.Normal font.bold: textType === MyText.TextType.Heading font.pixelSize: textType === MyText.TextType.Heading ? 24 : 12 }
有关QML中枚举使用的更多信息,请参阅 QML值类型 枚举 文档。
在Qt 5.10中引入了在QML中声明枚举的能力。
© 2024 Qt公司。本文档中的贡献为各自所有者的版权。本提供的文档是根据自由软件基金会发布的 GNU自由文档许可证版本1.3 的条款许可的。Qt及其相关标志是芬兰和/或其他国家的Qt公司注册的商标。所有其他商标均为各自所有者的财产。