Различные делегаты для QML ListView
Я хотел бы знать, можно ли использовать (несколько) разных делегатов для QML ListView
.
В зависимости от отдельного объекта в модели ListView
я хотел бы визуализировать объекты с разными делегатами.
Этот фрагмент кода объясняет, чего я хочу достичь:
main.qml
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 640
height: 480
visible: true
ListModel {
id: contactsModel
ListElement {
name: "Bill Smith"
position: "Engineer"
}
ListElement {
name: "John Brown"
position: "Engineer"
}
ListElement {
name: "Sam Wise"
position: "Manager"
}
}
ListView {
id: contactsView
anchors.left: parent.left
anchors.top: parent.top
width: parent.width
height: parent.height
orientation: Qt.Vertical
spacing: 10
model: contactsModel
delegate: {
if (position == "Engineer") return Employee; //<--- depending on condition, load Contact{}
else if (position == "Manager") return Manager; //<--- depending on condition, load Person{}
}
}
}
Employee.qml (Один из возможных компонентов, который я хотел бы использовать в качестве делегата)
import QtQuick 2.4
Rectangle{
width: 200
height: 50
color: ListView.isCurrentItem ? "#003366" : "#585858"
border.color: "gray"
border.width: 1
Text{
anchors.centerIn: parent
color: "white"
text: name
}
}
Manager.qml (другой компонент, который я хотел бы использовать в качестве делегата)
import QtQuick 2.4
Rectangle{
width: 200
height: 50
color: "red"
border.color: "blue"
border.width: 1
Text{
anchors.centerIn: parent
color: "white"
text: name
}
}
Буду признателен за любой совет!
Спасибо!
Ответы
Ответ 1
Я считаю, что было бы лучше реализовать один базовый делегат для всех типов position
, который загружает конкретную реализацию в зависимости от position
или любых других свойств данных, используя Loader
BaseDelegate {
property var position
Loader {
sourceComponent: {
switch(position) {
case "Engineer": return engineerDelegate
}
}
}
Component {
id: engineerDelegate
Rectangle {
Text { }
}
}
}
Ответ 2
У меня была такая же проблема, документация Qt дает довольно хороший ответ: http://doc.qt.io/qt-5/qml-qtquick-loader.html#using-a-loader-within-a-view-delegate
Самое простое решение - встроенный Component
с Loader
для установки файла source
:
ListView {
id: contactsView
anchors.left: parent.left
anchors.top: parent.top
width: parent.width
height: parent.height
orientation: Qt.Vertical
spacing: 10
model: contactsModel
delegate: Compenent {
Loader {
source: switch(position) {
case "Engineer": return "Employee.qml"
case "Manager": return "Manager.qml"
}
}
}
}
Любая попытка использовать Loader.srcComponent
приведет к отсутствию любой переменной из модели (включая index
). Единственный способ присутствия переменных - дети Component
находиться внутри основного Component
, но тогда может присутствовать только один, поэтому он бесполезен.
Ответ 3
Я реализовал его следующим образом:
ListView {
id: iranCitiesList
model: sampleModel
delegate: Loader {
height: childrenRect.height
width: parent.width
sourceComponent: {
switch(itemType) {
case "image" :
return imageDel;
case "video":
return videoDel;
}
}
}
ImageDelegate { id: imageDel }
VideoDelegate { id: videoDel }
}
ImageDelegate.qml
Component {
Image { /*...*/ }
}
VideoDelegate.qml
Component {
Item { /*....*/ }
}
В последнем случае проверьте ширину и высоту делегатов. В моем случае мне пришлось снова установить ширину и высоту моего делегата в Loader
.
Удачи - Мусави
Ответ 4
Поскольку у вас есть только два типа, следующий код так же прост в обслуживании, как легко понять:
delegate: Item {
Employee { visible = position === "Engineer" }
Manager { visible = position === "Manager" }
}
В случае, если число типов будет расти, это не подходящее решение, которое легко приводит к утверждению ада.
Ответ 5
Конечно, это возможно. ListView.delegate
- это своего рода указатель на Component
, который будет рисовать элементы, чтобы вы могли его изменить.
Например:
Employee { id: delegateEmployee }
Manager { id: delegateManager}
...
ListView {
property string position
delegate: position == "Engineer" ? delegateEmployee : delegateManager
}