0

虽然我已经想通了,但还是花了很长时间。如果您知道一个不那么复杂的解决方案 - 请分享。

我想提供一个View适用于任何类型model(带有任意命名的字段)的自定义:

  • model: 3
  • model: [ "red", "yellow", "green" ]
  • model: [ {color: "red"}, {color: "yellow"}, {color: "green"} ]
  • model: ListModel{ ListElement{color: "red"}; ListElement{color: "green"} }
  • 子类QAbstractItemModel等...

为此,我决定property Component delegate为该用户提供一个视觉效果,该视觉效果Item将插入到我的View.

但是,View还需要从中访问一些信息,delegate否则它会促进不必要的代码重复或代理的不必要的复杂性model

MyView {
     mymodel: ["red", "blue"]
     mydelegate: Text {
         text: "color=" + modelData.name
         must_also_somehow_set_color_of_MyView_element_to: modelData.color
     }
}

...其中 MyView 应该是这样的:

Column {
    Repeater {
        model: mymodel
        delegate: Rectangle {
            color: somehow_get_color_from_mydelegate
            Text {} // <--- instantiate mydelegate here with data from mymodel
        }
    }
}

这样做似乎很容易,但幼稚的尝试并没有奏效。作为答案发布的解决方案对我有用。

4

2 回答 2

0

诀窍是ormodel可见的包含所有可见的内容,包括and 。RepeaterInstantiatordelegatedelegateindexmodelData

model可以用作参数来ListModel.append()创建ListModel具有单个元素的。

然后它可以作为 a 分配model给 a Repeater,这将加载delegateQML 通常从View'smodel的元素中派生的所有上下文属性的副本indexmodelData以及model它本身。

在实例化时,Repeater/Instantiator触发onItemAdded/onObjectAdded信号,它可以用作获取对View's实例的引用的提示delegate

View可以要求 的用户在 中提供一个根,property该根delegate将存储获得/计算的值,可供 aView

或者,View可以包含另一个RepeaterInstantiator请求另一个delegate来获取它自己需要的值。或者一个容器类型可以同时封装View数据和视觉Item

例子:

我的视图.qml

import QtQuick 2.0
import QtQml.Models 2.1
Column {
    property var mymodel
    property Component mydelegate

    Repeater {
        model: mymodel
        delegate: Rectangle {
            width: childrenRect.width; height: childrenRect.height

            //color: model.color //works if "mymodel" has role "color"
            property var myitem: null //this will hold instance of mydelegate
            color: ( null !== myitem
                     && undefined !== myitem.bgcolor ) 
                     ? myitem.bgcolor : "transparent" //reads property of mydelegate

            // <-- mydelegate will be injected here
            Repeater {
                delegate: mydelegate
                model: ListModel{
                    Component.onCompleted: append(model)
                }
                onItemAdded: myitem = item
                onItemRemoved: myitem = null
            }
        }
    }
}

UsageExamples.qml

import QtQuick 2.0
import QtQuick.Window 2.0
Window{
    visible: true
    Row {
        spacing: 10

        MyView {
            mymodel: ListModel {
                ListElement{ name: "roses"; color: "red";   }
                ListElement{ name: "violets"; color: "blue";   }
            }
             mydelegate: Text {
                 text: name
                 property color bgcolor: model.color
             }
        }

        MyView {
             mymodel: [{name: "roses", color: "red"}, {name: "violets", color: "blue"}]
             mydelegate: Text {
                 text: modelData.name
                 property color bgcolor: modelData.color
             }
        }

        MyView {
             mymodel: ["red", "blue"]
             mydelegate: Text {
                 text: "color="+modelData
                 property color bgcolor: modelData
             }
        }

    }
}
于 2022-01-23T18:21:27.197 回答
0

我认为你真的在寻找一个加载器来实例化委托,而不是第二个中继器。您还可以通过使用别名来简化一点。尝试这样的事情:

Column {
    property alias mymodel: repeater.model
    property Component mydelegate

    Repeater {
        id: repeater
        delegate: Rectangle {
            width: childrenRect.width; height: childrenRect.height

            color: ( null !== loader.item
                     && undefined !== loader.item.bgcolor ) 
                     ? loader.item.bgcolor : "transparent"

            Loader {
                id: loader
                sourceComponent: myDelegate
            }
        }
    }
}
于 2022-01-24T15:28:16.533 回答