首页 文章

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

提问于
浏览
13

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

所以,我想要做的是让每个调用提供一个委托,该委托被添加到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
  }
}

我们的想法是GridView委托中的Loader加载用户提供的委托,它看起来像这样:

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

但是,这不起作用 . QML报告“name”是Text元素中的未知变量 . 如果我用字符串替换name变量(即“hello”),它按预期工作 .

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

一个侧面问题是:有更好的方法吗?

3 回答

  • 4

    我这样解决了:

    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所有,因为整个模型都归该模型所有 . 因此,如果要在列表被销毁后使用该对象,则必须重新复制或复制它 .

  • 12

    只想在这里指出“grid.model.get(model.index)”:

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

    在当前背景下等同于“模型”:

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

    我正在回答我自己的问题,因为我一直在解决这个问题并找到了一个可接受的解决方案 . 我还没有回答这个问题,因为我想知道是否有更简单或更有效的解决方案 .

    以下是我解决这个问题的方法:我将Binding组件与Loader一起使用,并创建了一个自定义MyDelegate组件,该组件具有模型当前ListElement的variant属性 . 这是修改后的代码,其中包含注释标记的重要更改 .

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

    关键的补充是一个自定义MyDelegate组件,它将model属性定义为变体 . 这在解释时绑定,这意味着在引用模型的name属性时Main.qml中没有错误 .

    MyDelegate.qml

    import QtQuick 1.1
    
    Rectangle {
      property variant model
    }
    

    有些东西告诉我,有一种更简单的方法可以做到这一点,但现在这样做 .

相关问题