2011-12-09 4 views
13

Sto tentando di creare un componente QML riutilizzabile che ospita internamente un GridView. Ogni elemento in GridView ha un insieme di comportamenti (principalmente di visualizzazione e roba basata sul mouse) che è comune in tutta l'applicazione. Tuttavia, ciò che viene visualizzato all'interno degli elementi di GridView cambia a seconda del caso d'uso. (Ovvero, lo stesso Componente incapsulato per un GridView, ma altrove nell'applicazione potrebbe usare un Componente diverso.)QML: come posso passare le proprietà del modello a un delegato caricato all'interno di un delegato GridView (o ListView)?

Quindi, quello che vorrei fare è avere a ogni invocazione un delegato che viene aggiunto ad ogni elemento nel GridView, che è già un delegato. In altre parole, qualcosa di simile:

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

L'idea è che il caricatore all'interno del delegato GridView carica il delegato fornito dall'utente, che sarebbe simile a questa:

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

Tuttavia, questo non lo fa lavoro. QML riporta che "name" è una variabile sconosciuta all'interno dell'elemento Text. Se sostituisco la variabile name con una stringa (ad esempio "ciao"), funziona come previsto.

La mia domanda è, come posso passare la variabile "nome" a internalDelegate, o meglio ancora, rendere disponibile l'intero modello in modo che internalDelegate possa accedervi tutti (poiché anche il chiamante sta definendo il modello).

Una domanda secondaria è: c'è un modo migliore per farlo?

risposta

12

ho risolto in questo modo:

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

Non so se è "migliore", ma ha il codice di meno e più semplice. I modelli di lista sono un po 'scomodi e non molto coerenti in QML. E ricorda che model.get (index) è di proprietà di GridView perché l'intero modello è di proprietà di quello. Quindi se vuoi usare quell'oggetto dopo che la lista è stata distrutta devi ripararla o copiarla.

+0

Finii usando la tua tecnica per il mio progetto. Meno codice è migliore e mi piace come rimuove completamente la necessità del componente di bind. Grazie! –

4

Sto rispondendo alla mia domanda perché ho continuato a lavorare sul problema e ho trovato una soluzione accettabile. Non sto segnalando questa domanda come risposta (ancora) perché vorrei sapere se ci sono soluzioni più semplici o più efficienti.

Ecco come ho risolto questo problema: ho utilizzato il componente Binding con il programma di caricamento e creato un componente MyDelegate personalizzato con una proprietà variante per il ListElement corrente del modello. Ecco il codice modificato con modifiche importanti contrassegnate dai commenti.

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's properties via MyDelegate's 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's loaded 
     Binding { 
      target: loader.item 
      property: "model" 
      value: model 
      when: loader.status == Loader.Ready 
     } 
     } 
    } 

    model: parent.internalModel 
    } 
} 

L'aggiunta cruciale è un componente MyDelegate personalizzato, che definisce la struttura del modello come variante. Questo si lega al tempo di interpretazione, il che significa che non c'è alcun errore in Main.qml quando si fa riferimento alla proprietà del nome del modello.

MyDelegate.qml

import QtQuick 1.1 

Rectangle { 
    property variant model 
} 

Qualcosa mi dice che c'è un modo ancora più semplice per fare questo, ma questo funziona per ora.

12

Voglio solo sottolineare che "grid.model.get (model.index)" qui:

delegate: Row { 
     Loader { 
      sourceComponent: myGrid.internalDelegate 
      property QtObject modelData: grid.model.get(index) //< 
     } 
    } 

equivale a "modello" nel contesto attuale:

delegate: Row { 
     Loader { 
      sourceComponent: myGrid.internalDelegate 
      property QtObject modelData: model //< 
     } 
    } 
+1

grazie, quindi so che "QtObject" può essere un tipo di dati qml. – Brent81