2011-12-09 12 views
13

Estoy intentando construir un Componente QML reutilizable que aloje internamente un GridView. Cada elemento en GridView tiene un conjunto de comportamientos (en su mayoría elementos de pantalla y mouse) que es común en toda la aplicación. Sin embargo, lo que se muestra dentro de los elementos de GridView cambia según el caso de uso. (Es decir, el mismo componente encapsulado para un GridView, pero en otro lugar de la aplicación podría usar un Componente diferente).QML: ¿Cómo puedo pasar las propiedades del modelo a un delegado cargado dentro de un delegado GridView (o ListView)?

Entonces, lo que me gustaría hacer es que cada invocación suministre un delegado que se agrega a cada elemento en GridView, que ya es un delegado. En otras palabras, algo como esto:

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

La idea es que el cargador dentro del delegado GridView carga el delegado proporcionada por el usuario, lo que sería algo como esto:

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

sin embargo, esto no lo hace trabajo. QML informa que "nombre" es una variable desconocida dentro del elemento de texto. Si reemplazo la variable de nombre con una cadena (es decir, "hola"), funciona como se esperaba.

Mi pregunta es, ¿cómo puedo pasar la variable "nombre" a internalDelegate, o mejor aún, hacer que todo el modelo esté disponible para que endpoint interno pueda acceder a todos ellos (dado que la persona que llama también está definiendo el modelo).

Una pregunta complementaria es: ¿hay una mejor manera de hacerlo?

Respuesta

12

Lo resolvió así:

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 importación 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" 
      } 
     } 
    } 
} 

No sé si es "mejor", pero tiene menos y más simple código. Los modelos de lista son un poco incómodos y no son consistentes en QML. Y tenga en cuenta que model.get (index) es propiedad de GridView porque todo el modelo es propiedad de eso. Entonces, si desea usar ese objeto después de que se destruyó la lista, debe reemplazarlo o copiarlo.

+0

Yo hiero usando tu técnica para mi proyecto. Menos código es mejor y me gusta cómo elimina por completo la necesidad del componente vinculante. ¡Gracias! –

4

Estoy respondiendo mi propia pregunta porque seguí trabajando en el problema y encontré una solución aceptable. No estoy marcando esta pregunta como respondida (todavía) porque me gustaría saber si hay soluciones más fáciles o más eficientes.

Así resuelto este problema: utilicé el componente de enlace con el cargador y creé un componente MyDelegate personalizado que tiene una propiedad de variante para el elemento de lista actual del modelo. Aquí está el código modificado con cambios importantes marcados por comentarios.

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

La adición crucial es un componente MyDelegate personalizada, que define la propiedad de modelo como una variante. Esto se une al tiempo de interpretación, lo que significa que no hay ningún error en Main.qml cuando se hace referencia a la propiedad del nombre del modelo.

MyDelegate.qml

import QtQuick 1.1 

Rectangle { 
    property variant model 
} 

Algo me dice que hay una manera más fácil de hacer esto, pero esto funciona por ahora.

12

Sólo quiero señalar que "grid.model.get (model.index)" aquí:

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

es equivalente a "modelo" en el contexto actual:

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

gracias, entonces sé que "QtObject" puede ser un tipo de datos qml. – Brent81

Cuestiones relacionadas