QML: Как передать свойства модели делегату, загруженному внутри делегата GridView (или ListView)?
Я пытаюсь создать повторно используемый компонент QML, который внутренне размещает GridView. Каждый элемент в 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 загружает предоставленный пользователем делегат, который будет выглядеть примерно так:
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 сообщает, что "имя" является неизвестной переменной внутри элемента "Текст". Если я заменю переменную имени на строку (т.е. "Привет" ), она будет работать как ожидалось.
Мой вопрос в том, как передать переменную "имя" в innerDelegate, или, еще лучше, сделать всю модель доступной, так что internalDelegate может получить доступ ко всем из них (так как вызывающая сторона также определяет модель).
Вопрос: есть ли лучший способ сделать это?
Ответы
Ответ 1
Я решил это так:
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 импортировать 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, потому что вся модель принадлежит этому. Поэтому, если вы хотите использовать этот объект после уничтожения списка, вам нужно его повторно или скопировать.
Ответ 2
Просто хочу указать, что "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 //<
}
}
Ответ 3
Я отвечаю на свой вопрос, потому что продолжал работать над проблемой и нашел приемлемое решение. Я не отмечаю этот вопрос, как ответ (пока), потому что я хотел бы знать, есть ли более простые или более эффективные решения.
Вот как я решил эту проблему: я использовал компонент Binding с загрузчиком и создал пользовательский компонент MyDelegate, который имеет свойство варианта для текущего текущего элемента ListElement. Здесь измененный код с важными изменениями, отмеченными комментариями.
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 properties via MyDelegate 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 loaded
Binding {
target: loader.item
property: "model"
value: model
when: loader.status == Loader.Ready
}
}
}
model: parent.internalModel
}
}
Важным дополнением является пользовательский компонент MyDelegate, который определяет свойство модели как вариант. Это связывается во время интерпретации, то есть нет ошибки в Main.qml, когда ссылается на свойство имени модели.
MyDelegate.qml
import QtQuick 1.1
Rectangle {
property variant model
}
Что-то подсказывает мне еще более простой способ сделать это, но сейчас это работает.