我真的很喜欢QML。我喜欢如何定义组件(与类相比)及其属性,并从其他地方(与对象相比)实例化它们。
我可以说,一个按钮,有一些外观和感觉,上面有标签文字。例如,可以使用此组件定义(Button.qml
):
Item {
id: button
property string label
anchors.fill: parent
Rectangle {
anchors.fill: parent
radius: 10
color: "gray"
Text {
anchors.centerIn: parent
font.pixelSize: 20
text: button.label
color: "white"
}
}
}
并在此主文件(main.qml
)中实例化:
Rectangle {
width: 300
height: 200
Button {
anchors.centerIn: parent
anchors.margins: 50
label: "Hello button!"
}
}
但是我看到了以下限制:我只能定义一个带有一些属性的按钮模板 ,而不是一些占位符。实例中定义的所有子项都是直接子项,至少是默认值,我想改变这种行为。
假设我想在按钮中放置一个项目(让我们说一个图像,但我不想告诉Button
它将是一个图像的定义)。我想象这样的事情:
Item {
id: button
property Item contents <-- the client can set the placeholder content here
anchors.fill: parent
Rectangle {
anchors.fill: parent
radius: 10
color: "gray"
Item {
id: placeholder <-- where the placeholder should be inserted
}
}
Component.onCompleted: {
// move the contents into the placeholder...
}
}
我怎样才能做到这一点?我不知道使用Component.onCompleted
是否正确。但请注意,在我的情况下,内容将永远不会改变(至少在我当前的应用程序设计中......)。
另外,我希望锚定在占位符中工作。例如,如果我将内容定义为Text元素,则以其父元素为中心(首先是模板本身)。然后我的代码将此Text实例移动到占位符中,然后父锚点应该是占位符项的那些,而不是模板项。
答案 0 :(得分:32)
我在2011年Qt开发者日"Qt Quick Best Practices and Design Patterns"的演示文稿中提出了一个更好的答案。
他们将default property alias ...
alias 子项目用于任何项目的任何属性。如果您不想为 children 添加别名但为别名属性指定名称,只需删除default
即可。 (文字子项是每个QML定义的默认属性的值。)
Item {
id: button
default property alias contents: placeholder.children
anchors.fill: parent
Rectangle {
anchors.fill: parent
radius: 10
color: "gray"
Item {
id: placeholder <-- where the placeholder should be inserted
}
}
}
答案 1 :(得分:5)
Necro回答以防其他人像我一样在这里结束。
在Qt5沿线的某处,默认属性变为“data”而不是“儿童”。 这使得可以添加除“Item”之外的其他对象类型。 例如也可以添加连接(以回答我上面提到的问题)
所以在Qt5中你应该这样做:
Item {
id: button
default property alias contents: placeholder.data
anchors.fill: parent
Rectangle {
anchors.fill: parent
radius: 10
color: "gray"
Item {
id: placeholder <-- where the placeholder should be inserted
}
}
}
注意:
placeholder.data
代替placeholder.children
另请注意,您不必使用别名contents
- 这可以是您喜欢的任何内容。一个例子:
Item {
id: button
default property alias foo: placeholder.data
...
}
答案 2 :(得分:3)
实际上,我所听到的正确答案是使用QML Loader来完成你想要的。
[正如所说;我还没有真正尝试过,但它是在我的近期试用清单上看起来相当直接]
此外,搜索其他"QML Loader"个问题的stackoverflow,因为有一个数字可以帮助您入门。
答案 3 :(得分:1)
您可以使用以下代码移动项目(如果您想支持占位符中的多个项目):
property list<Item> contents
Component.onCompleted: {
var contentItems = [];
for(var i = 0; i < contents.length; ++i)
contentItems.push(contents[i]);
placeholder.children = contentItems;
}
请注意,您不必为contents属性提供Items列表,因为QML引擎也会为列表属性接受单个值。
答案 4 :(得分:1)
简而言之(表明想法):
import QtQuick 1.1
Item {
width: 200
height: 100
//<-- the client can set the placeholder content here
property Item contents: Rectangle {
anchors.fill: parent
anchors.margins: 25
color: "red"
}
Rectangle {
id: container
anchors.fill: parent
radius: 10
color: "gray"
//<-- where the placeholder should be inserted
}
Component.onCompleted: {
contents.parent = container
}
}
稍长版本(支持内容重新分配):
import QtQuick 1.1
Item {
width: 200
height: 100
//<-- the client can set the placeholder content here
property Item contents: Rectangle {
//anchors can be "presupplied", or set within the insertion code
//anchors.fill: parent
//anchors.margins: 25
color: "red"
}
Rectangle {
id: container
anchors.fill: parent
radius: 10
color: "gray"
//<-- where the placeholder should be inserted
//Item {
// id: placeholder
//}
}
//"__" means private by QML convention
function __insertContents() {
// move the contents into the placeholder...
contents.parent = container
contents.anchors.fill = container
contents.anchors.margins = 25
}
onContentsChanged: {
if (contents !== null)
__insertContents()
}
Component.onCompleted: {
__insertContents()
}
}
希望这会有所帮助:)