Различные делегаты для 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
    }
}

Буду признателен за любые советы! Спасибо!

19
задан 13.08.2015, 19:58

5 ответов

Я считаю, что было бы лучше реализовать один базовый делегат для всех видов position, который загружает конкретную реализацию в зависимости от position или любых других свойств данных, используя Loader

BaseDelegate {
    property var position

    Loader {
        sourceComponent: {
            switch(position) {
                case "Engineer": return engineerDelegate
            }
        }
    }

    Component {
        id: engineerDelegate
        Rectangle {
             Text {  }
        }
    }
}
11
ответ дан 21.10.2019, 14:49

У меня была та же проблема, документация 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, но тогда может присутствовать только один, поэтому это бесполезно.

15
ответ дан 21.10.2019, 14:49
  • 1
    @pavel благодарит указать на пропавших без вести знак, но Вы видите от метки времени, они были отправлены одновременно. – Taryn♦ 16.02.2020, 02:18

Я реализовал это следующим образом:

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.
Удачи - Мусави

8
ответ дан 21.10.2019, 14:49

Поскольку у вас есть только два типа, следующий код так же легко поддерживать и легко понять:

delegate: Item {
    Employee { visible = position === "Engineer" }
    Manager { visible = position === "Manager" }
}

В случае, если число типов будет расти, это не подходящее решение для это легко приводит к адскому утверждению if.

0
ответ дан 21.10.2019, 14:49

Конечно, это возможно. ListView.delegate является своего рода указателем на Component, который будет рисовать элементы, чтобы вы могли их изменить.

Например:

Employee { id: delegateEmployee }
Manager { id: delegateManager}
...
ListView {  
    property string position   
    delegate: position == "Engineer" ? delegateEmployee : delegateManager
}
-1
ответ дан 21.10.2019, 14:49

Теги

Похожие вопросы