【问题标题】:Binding specific item of a ListModel to a Component将 ListModel 的特定项绑定到组件
【发布时间】:2017-04-07 22:50:43
【问题描述】:

我正在使用 HsQML 构建应用程序。这是我第一次接触 QML,第二次接触 Qt,也是第一次接触 Haskell 的大型项目,请原谅我的无知。

在 UI 中,我有一个 TabView。第一个选项卡包含一个绑定到模型并显示项目列表的 ListView。双击 ListView 中的项目会打开一个新选项卡,其中包含正确显示该项目详细信息的组件(我的猜测是由于新选项卡从被单击的列表项继承其上下文)。

现在,我的目标是打开一个选项卡,在其中为该模型创建一个新项目。这个想法是创建一个空白数据项(可选地将其添加到模型中),并将其“加载”到用于编辑现有项的相同组件类型中。我搜索了 QML 的文档,甚至找不到任何与远程相关的东西,这让我觉得这种方法完全有缺陷。

TabView {
    id : rootTabs

    Tab {
        ListView {
            model : AutoListModel {
                source : workflowModel // this is sort of HsQML specific, data comes as a list from Haskell
            }
            delegate : Rectangle {
                Text {
                    text : modelData.name
                }

                MouseArea {
                    anchors.fill : parent

                    // this part works because the new component inherits its modelData from the current context
                    // so the new tab has correct data
                    onDoubleClicked : {
                        rootTabs.addTab(modelData.name, Qt.createComponent("WorkflowView.qml"))
                        rootTabs.currentIndex = rootTabsCount - 1
                    }
                }
            }
        }

        Button {
            text : "Create workflow"

            // this is the part in question - how do I assign the newly appended data to comp?
            onClicked : {
                wModel.appendBlank()
                comp = Qt.createComponent("WorkflowView.qml")
                var tab = rootTabs.addTab("New workflow", comp)
                comp.statusChanged.connect(tabLoaded)
            }
        }
    }
}

WorkflowEdit.qml:

Rectangle {
    TextField {
        id : nameInput
        text : modelData.name
        Binding {
            target : modelData
            property : "name"
            value : nameInput.text
        }
    }
}

【问题讨论】:

  • 新标签有正确数据是什么意思?看起来您只是在创建一个 WorkflowView 组件,仅此而已。您可以发布该 qml 文件的代码吗?
  • 正确,我只是在创建一个 WorkflowView。但是,当通过双击 ListView 项目创建它时,它的 modelData 似乎包含该项目的相应数据......这完全是魔术。现在,我希望能够以编程方式执行相同的操作,以便WorkflowViewmodelData 将引用我想要的模型中的项目。添加了一个示例WorkflowView,反正真的很简单。

标签: qt haskell qml hsqml


【解决方案1】:

我想我有你要找的东西。这有点棘手,因为 Tab 本质上是加载程序。这是为 Tab QML 类型创建一个额外属性作为存储模型索引的地方的问题。由于选项卡只是 TabView 的子项,因此新选项卡可以作为 TabView 的父项,而不是使用 addTab() 方法。请注意,对于我的模型,我使用了 ListModel。

ma​​in.qml

import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Window 2.2

Window {
    visible: true
    width: 640
    height: 480

    TabView {
        id : rootTabs
        anchors.fill: parent

        ListModel {
            id: listModel
            ListElement { car: "Toyota" }
            ListElement { car: "Chevrolet" }
            ListElement { car: "Honda" }
            ListElement { car: "Daihatsu" }
            ListElement { car: "Ford" }
            ListElement { car: "Nissan" }
            ListElement { car: "Hyundai" }
            ListElement { car: "Acura" }
        }

        MyTab {
            title: "Default"

            Item {

                ListView {
                    id: listView
                    anchors { fill: parent; bottomMargin: 240 }
                    model : listModel

                    delegate : Rectangle {
                        width: parent.width
                        height: 40
                        Text {
                            text : car
                            color: "black"
                            font.pointSize: 20
                        }

                        MouseArea {
                            anchors.fill : parent
                            onDoubleClicked : {
                                var myTab = Qt.createComponent("MyTab.qml")
                                var workflow = Qt.createComponent("Workflow.qml")
                                myTab.createObject(rootTabs, { "title": car, "modelIndex": index, "sourceComponent": workflow });
                                rootTabs.currentIndex = rootTabs.count - 1
                            }
                        }
                    }
                }

                Button {
                    anchors {fill: parent; topMargin: 240 }
                    text : "Create workflow"

                    onClicked : {
                        listModel.append( { "car" : "New car" } )
                        var myTab = Qt.createComponent("MyTab.qml")
                        var workflow = Qt.createComponent("Workflow.qml")
                        myTab.createObject(rootTabs, { "title": "New Workflow", "modelIndex": listModel.count - 1 , "sourceComponent": workflow });
                    }
                }
            }
        }
    }
}

MyTab.qml

import QtQuick 2.0
import QtQuick.Controls 1.4

Tab {
    property int modelIndex
}

Workflow.qml

import QtQuick 2.0
import QtQuick.Controls 1.4

Rectangle {
    TextField {
        id : nameInput
        text : listModel.get(modelIndex).car
        onTextChanged: {
            // Update model using modelIndex. Observe updates in listview
            listModel.set(modelIndex, { "car" : text })
        }
    }
}

【讨论】:

  • 做到了!似乎有两个陷阱 - 1) 创建后选项卡项目上的设置属性无法正常工作,因此使用 createObject 手动解决了这个问题。此 imo 的正确解决方案是向 addTab 公开与 addObject 相同的配置(并且可能无论如何都在幕后调用它。2) 将任意对象分配给属性失败。我想知道这是否与我使用 HsQML 而不是我自己创建 QObjects 有关。解决方法是在模型的 int 属性上设置一个索引,然后每次都进行查找。
【解决方案2】:

TabView::addTab 返回一个Tab 对象,它基本上是一个Loader 对象。 Loader::item 是当前加载的对象。所以,解决方法是在tab中添加一个新的空模型数据如下(在Button::onClicked中):

var tab = ...
tab.loaded.connect(function () {tab.item.data = newModelData;}); // newModelData = wModel.appendBlank() ???

您应该将属性 modelData 显式添加到 WorkflowEdit.qml:

Rectangle {
    property var data: modelData // create property data and assign the context variable modelData to it by default
    TextField {
        id : nameInput
        text : data === undefined ? "" : data.name
        Binding {
            target : data
            property : "name"
            value : nameInput.text
        }
    }
}

【讨论】:

  • 在创建函数和选项卡的statusChanged 处理程序中都试过这个,得到Error: Cannot assign to non-existent property "modelData"。还尝试分配给component.modelData 而不是选项卡 - 这不会显示错误,但仍然不起作用,modelData 在 WorkflowView 中继续未定义。
  • 我扩展了我的答案来解决你提出的问题。
  • 该死,我知道这应该如何解决未定义的属性问题,但仍然无法正常工作:(我收到QML WorkflowEditView: Binding loop detected for property "modelData"(据我所知只是一个警告),当我激活tab: TypeError: Cannot read property 'name' of undefined. For the latter, as I mentioned already I tried setting the model both when creating the tab, and when the tab becomes ready, and neither works. Btw I assign to component.modelData, since the property is defined on组件而不是选项卡。
  • 我改变了三件事:(1)将modelData重命名为data以避免命名冲突(2)你绝对应该在tab.item上设置数据(而不是tabcomponent)(3)检查数据是否未定义以避免警告
  • 现在我在分配给tab.item.data 的行上得到了一个相当通用的TypeError: Type error。我想这可能与我从后端传递数据的方式有关......
猜你喜欢
  • 1970-01-01
  • 2012-12-02
  • 2012-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多