我正在尝试构建一个内部托管GridView的可重用QML组件。 GridView中的每个元素都有一组在整个应用程序中很常见的行为(主要是显示和基于鼠标的东西)。但是,GridView元素内显示的内容会根据用例而改变。 (也就是说,一个GridView的封装组件相同,但在应用程序的其他地方,它可能使用不同的组件。)
所以,我想要做的是让每个调用提供一个委托,该委托被添加到GridView中的每个元素,该元素已经是委托。换句话说,就像这样:
MyGrid.qml
import QtQuick 1.1
Rectangle {
id: myGrid
objectName: "myGrid"
property Component internalDelegate
property variant internalModel
GridView {
anchors.fill: parent
delegate: Row {
Loader {
sourceComponent: myGrid.internalDelegate
}
}
model: parent.internalModel
}
}
想法是GridView委托中的Loader加载用户提供的委托,它看起来像这样:
Main.qml
import QtQuick 1.1
Rectangle {
anchors.fill: parent
width: 300
height: 200
MyGrid {
anchors.fill: parent
internalDelegate: Text {
text: name
}
internalModel: ListModel {
ListElement {
name: "a"
}
ListElement {
name: "b"
}
}
}
}
然而,这不起作用。 QML报告“name”是Text元素中的未知变量。如果我用字符串替换name变量(即“hello”),它将按预期工作。
我的问题是,如何将“name”变量传递给internalDelegate,或者更好的是,使整个模型可用,以便internalDelegate可以访问所有这些变量(因为调用者也在定义模型)。
一个附带问题是:有更好的方法吗?
答案 0 :(得分:12)
MyGrid.qml
import QtQuick 1.1
Rectangle {
id: myGrid
objectName: "myGrid"
property Component internalDelegate
property variant internalModel
GridView {
id: grid
anchors.fill: parent
delegate: Row {
Loader {
sourceComponent: myGrid.internalDelegate
property variant modelData: grid.model.get(index)
}
}
model: parent.internalModel
}
}
main.qml
import QtQuick 1.1
Rectangle {
anchors.fill: parent
width: 300
height: 200
MyGrid {
anchors.fill: parent
internalDelegate: Text {
text: modelData.name
}
internalModel: ListModel {
ListElement {
name: "a"
}
ListElement {
name: "b"
}
}
}
}
不知道它是否更好",但它的代码更少,更简单。列表模型有点尴尬,在QML中并不是真的一致。 请记住,model.get(index)归GridView所有,因为整个模型都归该模型所有。因此,如果要在列表被销毁后使用该对象,则必须重新复制或复制它。
答案 1 :(得分:12)
只想在这里指出“grid.model.get(model.index)”:
delegate: Row {
Loader {
sourceComponent: myGrid.internalDelegate
property QtObject modelData: grid.model.get(index) //<
}
}
在当前背景下等同于“模型”:
delegate: Row {
Loader {
sourceComponent: myGrid.internalDelegate
property QtObject modelData: model //<
}
}
答案 2 :(得分:4)
我正在回答我自己的问题,因为我一直在解决这个问题并找到了一个可以接受的解决方案。我还没有回答这个问题,因为我想知道是否有更简单或更有效的解决方案。
以下是我如何解决这个问题:我将Binding组件与Loader一起使用,并创建了一个自定义MyDelegate组件,该组件具有模型当前ListElement的variant属性。这是修改过的代码,其中包含由注释标记的重要更改。
<强> Main.qml 强>
import QtQuick 1.1
Rectangle {
anchors.fill: parent
width: 300
height: 200
MyGrid {
anchors.fill: parent
// *** Use MyDelegate rather than generic Component and refer to
// *** model's properties via MyDelegate's model property
internalDelegate: MyDelegate {
Text {
text: model.index + model.name
}
}
internalModel: ListModel {
ListElement {
name: "a"
}
ListElement {
name: "b"
}
}
}
}
<强> MyGrid.qml 强>
import QtQuick 1.1
Rectangle {
id: myGrid
objectName: "myGrid"
property Component internalDelegate
property variant internalModel
GridView {
anchors.fill: parent
delegate: Row {
Loader {
id: loader
sourceComponent: myGrid.internalDelegate
// *** Bind current model element to the component
// *** when it's loaded
Binding {
target: loader.item
property: "model"
value: model
when: loader.status == Loader.Ready
}
}
}
model: parent.internalModel
}
}
关键的补充是一个自定义的MyDelegate组件,它将model属性定义为变体。这在解释时绑定,这意味着在引用模型的name属性时Main.qml中没有错误。
<强> MyDelegate.qml 强>
import QtQuick 1.1
Rectangle {
property variant model
}
有些东西告诉我,有一种更简单的方法可以做到这一点,但现在这样做。