如何制作一些可重用的 QML 对象,它可以注入另一个 QML 对象?
How to make some reusable QML object, which can inject another QML object?
如何制作一些可重用的 QML 对象,它可以注入另一个对象?
我曾尝试使用 Component
& Loader
,但似乎不是我想要的。 (还是封装了整个QML类型,缺乏弹性,难以复用)
用法示例:
Card.qml
import QtQuick 2.0
import QtQuick.Layouts 1.3
Rectangle {
default property var innerObject
property string titleText: "[Hello Untitled Title]"
id: root
color: "#fff"
ColumnLayout {
anchors.fill: parent
Rectangle {
id: header
height: 10
width: parent.width
color: "#666"
RowLayout {
Text { text: titleText; color: "#fff" }
}
}
// How to inject innerObject in here ?
}
}
main.qml
import QtQuick 2.0
import QtQuick.Layouts 1.3
Card {
titleText: "Image Information"
ColumnLayout { /* .......*/ } // innerObject
}
Card {
titleText: "Image Viewer"
Rectangle { /* .......*/ } // innerObject
}
对组件使用 Loader
不是强制性的。你可以去:
Loader {
source: "Something.qml"
}
当源是可以同步加载的东西时,你可以直接使用加载器的item
来进行绑定之类的东西,而不用担心它是否被创建。如果您通过网络加载,您必须延迟绑定直到项目完成,并使用 Binding
元素或 Qt.binding()
以声明或命令的方式分别完成。
在您的情况下,加载程序是合适的,而内部动态对象的 属性 不是 Component
。通过这种方式,您可以使用内联组件或现有源中的 Qt.createComponent()
填充它。
property Component innerObject
...
innerObject: Component { stuff }
...
innerObject: Qt.CreateComponent(source)
当然,还有更高级的方法可以做到,比如我概述的"generic QML model object"。它允许以声明式和命令式的方式快速轻松地创建任意数据结构树,并且由于该对象也是一个模型,您可以直接使用列表视图或带重复器的定位器元素来布局 gui,而无需实际编写每个 UI 代码和每一次。
此外,根据您的 main.qml
代码示例 - 在一个 qml 文件中不能有多个根元素。
编辑:如果元素被移动到它自己的 qml 文件,default property
方法实际上有效,所以基本上你也可以:
default property alias innerObject: innerColumn.children
其中 innerColumn
是您的 ColumnLayout
的 ID。此外,innerObject
可以是任何合法名称,因为作为默认值 属性,它实际上不会被使用。
还可以选择不使用默认值属性,这在根项仍然需要有自己的子项但仍然有能够将声明对象重定向为子对象的子对象:
property alias content: innerColumn.children
// and then
content: [ Obj1{}, Obj2{}, Obj3{} ] // will become children of innerColumn
我链接的答案是这样的:
Main.qml
Card {
titleText: "Image Viewer"
innerObject: Rectangle {
Component.onCompleted: {
console.log(parent.objectName)
}
}
}
Card.qml
Rectangle {
property string titleText: "[Hello Untitled Title]"
default property alias innerObject : innercolumn.children
id: root
color: "#fff"
ColumnLayout {
id: innercolumn
objectName: "column"
anchors.fill: parent
Rectangle {
id: header
height: 10
width: parent.width
color: "#666"
RowLayout {
Text { text: titleText; color: "#fff" }
}
}
}
}
我还想提出一个基于默认 属性 和重新设置父级的解决方案:
可以嵌入另一个项目的项目:
MyItem.qml
import QtQuick 2.7
import QtQuick.Layouts 1.2
Rectangle {
id: root
default property Item contentItem: null
border {
width: 1
color: "#999"
}
ColumnLayout {
anchors.fill: parent
Rectangle {
Layout.fillWidth: true
height: 30
color: "lightgreen"
}
Item {
id: container
Layout.fillWidth: true
Layout.fillHeight: true
}
}
onContentItemChanged: {
if(root.contentItem !== null)
root.contentItem.parent = container;
}
}
可以如下使用:
main.qml
import QtQuick 2.7
import QtQuick.Window 2.0
Window {
visible: true
width: 600
height: 600
MyItem{
width: 400
height: 400
anchors.centerIn: parent
Text {
text: "Hello!"
anchors.centerIn: parent
}
}
}
但我仍然同意@ddriver 的观点,Loader
是这种情况下的最佳解决方案
如何制作一些可重用的 QML 对象,它可以注入另一个对象?
我曾尝试使用 Component
& Loader
,但似乎不是我想要的。 (还是封装了整个QML类型,缺乏弹性,难以复用)
用法示例:
Card.qml
import QtQuick 2.0
import QtQuick.Layouts 1.3
Rectangle {
default property var innerObject
property string titleText: "[Hello Untitled Title]"
id: root
color: "#fff"
ColumnLayout {
anchors.fill: parent
Rectangle {
id: header
height: 10
width: parent.width
color: "#666"
RowLayout {
Text { text: titleText; color: "#fff" }
}
}
// How to inject innerObject in here ?
}
}
main.qml
import QtQuick 2.0
import QtQuick.Layouts 1.3
Card {
titleText: "Image Information"
ColumnLayout { /* .......*/ } // innerObject
}
Card {
titleText: "Image Viewer"
Rectangle { /* .......*/ } // innerObject
}
对组件使用 Loader
不是强制性的。你可以去:
Loader {
source: "Something.qml"
}
当源是可以同步加载的东西时,你可以直接使用加载器的item
来进行绑定之类的东西,而不用担心它是否被创建。如果您通过网络加载,您必须延迟绑定直到项目完成,并使用 Binding
元素或 Qt.binding()
以声明或命令的方式分别完成。
在您的情况下,加载程序是合适的,而内部动态对象的 属性 不是 Component
。通过这种方式,您可以使用内联组件或现有源中的 Qt.createComponent()
填充它。
property Component innerObject
...
innerObject: Component { stuff }
...
innerObject: Qt.CreateComponent(source)
当然,还有更高级的方法可以做到,比如我概述的"generic QML model object"
此外,根据您的 main.qml
代码示例 - 在一个 qml 文件中不能有多个根元素。
编辑:如果元素被移动到它自己的 qml 文件,default property
方法实际上有效,所以基本上你也可以:
default property alias innerObject: innerColumn.children
其中 innerColumn
是您的 ColumnLayout
的 ID。此外,innerObject
可以是任何合法名称,因为作为默认值 属性,它实际上不会被使用。
还可以选择不使用默认值属性,这在根项仍然需要有自己的子项但仍然有能够将声明对象重定向为子对象的子对象:
property alias content: innerColumn.children
// and then
content: [ Obj1{}, Obj2{}, Obj3{} ] // will become children of innerColumn
我链接的答案是这样的:
Main.qml
Card {
titleText: "Image Viewer"
innerObject: Rectangle {
Component.onCompleted: {
console.log(parent.objectName)
}
}
}
Card.qml
Rectangle {
property string titleText: "[Hello Untitled Title]"
default property alias innerObject : innercolumn.children
id: root
color: "#fff"
ColumnLayout {
id: innercolumn
objectName: "column"
anchors.fill: parent
Rectangle {
id: header
height: 10
width: parent.width
color: "#666"
RowLayout {
Text { text: titleText; color: "#fff" }
}
}
}
}
我还想提出一个基于默认 属性 和重新设置父级的解决方案:
可以嵌入另一个项目的项目:
MyItem.qml
import QtQuick 2.7
import QtQuick.Layouts 1.2
Rectangle {
id: root
default property Item contentItem: null
border {
width: 1
color: "#999"
}
ColumnLayout {
anchors.fill: parent
Rectangle {
Layout.fillWidth: true
height: 30
color: "lightgreen"
}
Item {
id: container
Layout.fillWidth: true
Layout.fillHeight: true
}
}
onContentItemChanged: {
if(root.contentItem !== null)
root.contentItem.parent = container;
}
}
可以如下使用:
main.qml
import QtQuick 2.7
import QtQuick.Window 2.0
Window {
visible: true
width: 600
height: 600
MyItem{
width: 400
height: 400
anchors.centerIn: parent
Text {
text: "Hello!"
anchors.centerIn: parent
}
}
}
但我仍然同意@ddriver 的观点,Loader
是这种情况下的最佳解决方案