Я хотел бы знать, возможно ли использовать (несколько) разных делегатов для 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
}
}
Буду признателен за любые советы! Спасибо!
Я считаю, что было бы лучше реализовать один базовый делегат для всех видов position
, который загружает конкретную реализацию в зависимости от position
или любых других свойств данных, используя Loader
BaseDelegate {
property var position
Loader {
sourceComponent: {
switch(position) {
case "Engineer": return engineerDelegate
}
}
}
Component {
id: engineerDelegate
Rectangle {
Text { }
}
}
}
У меня была та же проблема, документация Qt дает довольно хороший ответ: http://doc.qt.io/qt-5/qml-qtquick-loader.html#using-a- loader-Within-a-view-делегат
Самым простым решением является встроенный 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: Component {
Loader {
source: switch(position) {
case "Engineer": return "Employee.qml"
case "Manager": return "Manager.qml"
}
}
}
}
Any попытка использовать Loader.srcComponent
приведет к отсутствию какой-либо переменной в модели (включая index
). Единственный способ присутствия переменных - это дочерние элементы Component
находиться внутри основного Component
, но тогда может присутствовать только один, поэтому это бесполезно.
Я реализовал это следующим образом:
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
.
Удачи - Мусави
Поскольку у вас есть только два типа, следующий код так же легко поддерживать и легко понять:
delegate: Item {
Employee { visible = position === "Engineer" }
Manager { visible = position === "Manager" }
}
В случае, если число типов будет расти, это не подходящее решение для это легко приводит к адскому утверждению if.
Конечно, это возможно. ListView.delegate
является своего рода указателем на Component
, который будет рисовать элементы, чтобы вы могли их изменить.
Например:
Employee { id: delegateEmployee }
Manager { id: delegateManager}
...
ListView {
property string position
delegate: position == "Engineer" ? delegateEmployee : delegateManager
}