Qt QML:如何将模型属性传递给GridView(或ListView)委托中加载的委托?

Qt QML:如何将模型属性传递给GridView(或ListView)委托中加载的委托?,qt,listview,gridview,model,qml,Qt,Listview,Gridview,Model,Qml,我正在尝试构建一个可重用的QML组件,它在内部托管一个GridView。GridView中的每个元素都有一组在整个应用程序中常见的行为(主要是显示和基于鼠标的内容)。但是,GridView元素中显示的内容会根据用例的不同而变化。(也就是说,同一个封装组件用于一个GridView,但在应用程序的其他地方,它可能使用不同的组件。) 所以,我想做的是让每个调用提供一个委托,该委托被添加到GridView中的每个元素,它已经是一个委托了。换句话说,类似这样的事情: MyGrid.qml import Q

我正在尝试构建一个可重用的QML组件,它在内部托管一个GridView。GridView中的每个元素都有一组在整个应用程序中常见的行为(主要是显示和基于鼠标的内容)。但是,GridView元素中显示的内容会根据用例的不同而变化。(也就是说,同一个封装组件用于一个GridView,但在应用程序的其他地方,它可能使用不同的组件。)

所以,我想做的是让每个调用提供一个委托,该委托被添加到GridView中的每个元素,它已经是一个委托了。换句话说,类似这样的事情:

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
  }
}
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"
      }
    }
  }
}
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"
      }
    }
  }
}
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
  }
}
import QtQuick 1.1

Rectangle {
  property variant model
}
其思想是GridView委托中的加载程序加载用户提供的委托,其外观如下:

Main.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
  }
}
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"
      }
    }
  }
}
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"
      }
    }
  }
}
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
  }
}
import QtQuick 1.1

Rectangle {
  property variant model
}
然而,这不起作用。QML报告“name”是文本元素中的未知变量。如果我用一个字符串(即“hello”)替换name变量,它将按预期工作

我的问题是,如何将“name”变量传递给internalDelegate,或者更好的是,使整个模型可用,以便internalDelegate可以访问所有模型(因为调用方也在定义模型)


一个附带的问题是:有没有更好的方法来解决这个问题?

我在回答我自己的问题,因为我一直在研究这个问题,并找到了一个可以接受的解决方案。我没有把这个问题标记为已回答,因为我想知道是否有更简单或更有效的解决方案

我是如何解决这个问题的:我将绑定组件与加载程序一起使用,并创建了一个自定义MyDelegate组件,该组件具有模型当前ListElement的variant属性。下面是修改后的代码,其中有注释标记的重要更改

Main.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
  }
}
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"
      }
    }
  }
}
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"
      }
    }
  }
}
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
  }
}
import QtQuick 1.1

Rectangle {
  property variant model
}
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
  }
}
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"
      }
    }
  }
}
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"
      }
    }
  }
}
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
  }
}
import QtQuick 1.1

Rectangle {
  property variant model
}
关键的添加是自定义MyDelegate组件,它将模型属性定义为变量。这在解释时绑定,这意味着在引用模型的name属性时Main.qml中没有错误

MyDelegate.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
  }
}
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"
      }
    }
  }
}
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"
      }
    }
  }
}
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
  }
}
import QtQuick 1.1

Rectangle {
  property variant model
}
有些事情告诉我,有一种更简单的方法可以做到这一点,但这一方法目前仍然有效。

我是这样解决的:

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

import 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"
            }
        }
    }
}
不知道它是否“更好”,但它的代码更少、更简单。列表模型有点笨拙,在QML中并不完全一致。
请记住model.get(index)属于GridView,因为整个模型都属于它。因此,如果您想在列表被销毁后使用该对象,您必须重新复制或复制它。

只需指出“grid.model.get(model.index)”:

委托:行{
装载机{
sourceComponent:myGrid.internalDelegate
属性QtObject modelData:grid.model.get(索引)//<
}
}
相当于当前上下文下的“模型”:

    delegate: Row {
        Loader {
            sourceComponent: myGrid.internalDelegate
            property QtObject modelData: model //< 
        }
    }
委托:行{
装载机{
sourceComponent:myGrid.internalDelegate
属性QtObject modelData:模型//<
}
}

我最终用你的技术完成了我的项目。代码越少越好,我喜欢它完全消除了绑定组件的需要。谢谢