2015-08-13 16 views
10

Ich würde gerne wissen, ob es möglich ist, (mehrere) verschiedene Delegaten für eine QML ListView zu verwenden.Verschiedene Delegaten für QML ListView

Abhängig von dem einzelnen Objekt im Modell ListView möchte ich die Objekte mit verschiedenen Delegaten visualisieren.

Dieses Stück Code erklärt, was ich erreichen möchte:

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 (Eine mögliche Komponente, die ich als Delegierter verwenden möchten)

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 (andere Komponente, die ich gerne als Delegierter verwenden würde)

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 
    } 
} 

Ich würde mich über jeden Hinweis freuen! Danke!

+0

In diesem Fall können Sie auch die Erstellung eines eindeutigen 'delegate' berücksichtigen, der' position' in Bindungen verwendet, um seinen Aspekt zu ändern. Andernfalls können Sie einen 'Loader' verwenden, aber Sie müssen einige Informationen an das innere' Element' weiterleiten, d. H. An die echten Delegierten. Auch Folibis Lösung kann funktionieren, aber ich glaube nicht, dass es in diesem Fall so wäre, da "Position" selbst eine Rolle spielt. – BaCaRoZzo

+0

Warum definieren Sie nicht einfach einen 'Delegaten', der sowohl die' Rectangle's als auch das 'visible' Feld auf einer pro' position' Basis enthält? – skypjack

Antwort

-1

Sicher, es ist möglich. ListView.delegate ist eine Art Zeiger auf eine Component, die die Elemente zeichnet, so dass Sie es ändern können.

Zum Beispiel:

Employee { id: delegateEmployee } 
Manager { id: delegateManager} 
... 
ListView { 
    property string position 
    delegate: position == "Engineer" ? delegateEmployee : delegateManager 
} 
+0

Dies löst das Problem nicht, denn Sie müssen die "Position" definieren, bevor die Liste ausgefüllt wird. Daher wird der Delegate von einem Typ sein und sich nicht ändern, abhängig vom Inhalt des Elements. – skypjack

0

Soweit Sie nur zwei Typen haben, der folgende Code ist so einfach wie leicht zu pflegen, zu verstehen: die Anzahl der Arten

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

Im Falle wird wachsen, es ist keine geeignete Lösung für sie führt leicht zu einer Hölle von if-Anweisung.

9

Ich glaube, es wäre besser, eine Basis Delegat für alle Arten von position zu implementieren, die auf position oder anderen Daten Eigenschaften mit Hilfe Loader

BaseDelegate { 
    property var position 

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

    Component { 
     id: engineerDelegate 
     Rectangle { 
      Text { } 
     } 
    } 
} 
+0

Besteht das Risiko, dass Leistungsprobleme auftreten, wenn die Anzahl der Elemente hoch ist? Ich weiß, dass Loader's Komponenten nicht blockieren, aber er wird eine Menge von ihnen unter der Haube arbeiten. Liege ich falsch? – skypjack

+0

Es hängt von der Komplexität der Delegierten ab, aber nicht vom Loader. – Andrii

+1

@skypjack ['Loader's] (https://youtu.be/2zWtxmhfyVo?t=1737) sind süß. ;) – BaCaRoZzo

3

ich setzte es wie folgt in Abhängigkeit der konkreten Umsetzung lädt:

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 { /*....*/ } 
} 

Letzte Anmerkung, überprüfen Sie die Breite und Höhe der Delegierten. In meinem Fall musste ich die Breite und Höhe meines Delegierten erneut in Loader setzen.
Viel Glück - Mousavi

+0

Ich habe etwas über die Leistung geforscht. Es scheint, dass die Leistung sehr gut ist und keine Optimierung nötig ist. –

5

Ich hatte das gleiche Problem haben, ist die Qt-Dokumentation eine ziemlich gute Antwort zu geben: http://doc.qt.io/qt-5/qml-qtquick-loader.html#using-a-loader-within-a-view-delegate

Die einfachste Lösung ist ein Inline-Component mit einem Loader eine source Datei zu setzen:

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" 
      } 
     } 
    } 
} 

Jeder Versuch Loader.srcComponent zu verwenden fehlende jede Variable aus dem Modell führen wird (einschließlich index). Die einzige Möglichkeit für die Variablen ist es, die Kinder Component innerhalb der Haupt Component zu sein, aber dann kann nur eine vorhanden sein, also ist es nutzlos.

Verwandte Themen