如何从另一个 QML 访问和控制 ListModel 的内容

Posted

技术标签:

【中文标题】如何从另一个 QML 访问和控制 ListModel 的内容【英文标题】:How to access and control the content of a ListModel from another QML 【发布时间】:2018-02-20 17:29:57 【问题描述】:

我曾问过类似的问题here。但此解决方案仅适用于一页 QML 文件。我构建了一个包含许多页面的 QML 应用程序,因此我制作了一个包含添加/删除操作的收藏选项卡。喜欢的标签页有列表模型。在我看来,为了将任何页面添加到收藏列表中,需要从示例页面调用收藏列表模型,因此当用户单击操作时,应将该页面作为列表项添加到收藏页面.我有两个例子。第一个示例是单页 QML,它添加/删除列表项。但是第二个示例不会将示例页面添加/删除到收藏列表页面。如何使用 QML 或 Java Script 访问、保存和恢复列表模型的内容?谢谢。

第一个例子:

ma​​in.qml

import QtQuick 2.6
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.0
import Qt.labs.settings 1.0
ApplicationWindow
    id:main
    width: 640
    height: 480
    visible:true
    title: "Menu"
    property string datastore: ""
    property int countt2: 0
    Settings
        property alias datastore: main.datastore
        property alias mycount: main.countt2
    
    menuBar:MenuBar 
        Menu
        title: main.title
            Action 
                id:action2
                text: qsTr("On/Off")
                onTriggered:
                    countt2++
                    console.log("triggered works.Count/2: "+ countt2%2)
                    if(countt2%2==1)
                        console.log("it must be added")
                        dataModel.append( "title": "Application Tools" )
                    
                    else if(countt2%2==0)
                        console.log("list must be removed. count/2: "+countt2%2)
                        return dataModel.remove(dataModel.index)
                    
                
            
        
    
    Component.onCompleted: 
        if(datastore)
            dataModel.clear()
            var datamodel=JSON.parse(datastore)
            for (var i=0; i<datamodel.length; ++i) dataModel.append(datamodel[i])
        
        console.log("onCompleted works right now.")
    
    onClosing: 
        var datamodel = []
        for (var i=0;i<dataModel.count; ++i) datamodel.push(dataModel.get(i))
        datastore=JSON.stringify(datamodel)
        console.log("datastore: "+datastore)
    
        ListView 
            id:malist
            width: parent.width
            height: parent.height
            focus: true
            interactive: true
            clip: true
            model:FavModel
            id:dataModel
            
            delegate: ItemDelegate 
                width: parent.width
                text: model.title
            
        

FavModel.qml:

import QtQuick 2.0
ListModel 
    id:dataModel
    

第二个例子:

ma​​in.qml:

import QtQuick 2.6
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
import Fluid.Controls 1.0
import QtQuick.Window 2.3
ApplicationWindow
    id:main
    width: 640
    height: 480
    visible:true
    title: "Example App"
    initialPage:TabbedPage 
        title: main.title
        Tab
            title:"APPS"
        ListView 
            id:malist
            width: parent.width
            height: parent.height
            focus: true
            interactive: true
            clip: true
            model:ListModel 
            id:appModel
            ListElement  title: qsTr("Page1"); source: "qrc:/SampePage.qml" 
            
            delegate: ListItem 
                text: model.title
                onClicked: pageStack.push(model.source)
            
        
        
        Favourites
    

Favorites.qml:

import QtQuick 2.6
import QtQuick.Controls 2.0
import QtQuick.Controls.Material 2.0
import Fluid.Controls 1.0
Tab
    title:"FAVORITES"
ListView 
    id:favorites
    width: parent.width
    height: parent.height
    focus: true
    interactive: true
    clip: true
    model:FavModel 
    id:favModel
    
    delegate: ListItem 
        text: model.title
        onClicked: pageStack.push(model.source)
    


FavModel.qml:

import QtQuick 2.0

ListModel 
    id:dataModel
    

SamplePage.qml:

import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.2
import Fluid.Controls 1.0
import Qt.labs.settings 1.0
Page
    title:qsTr("Page1")
    appBar.maxActionCount: 2
    id:sampleapp
    property string datastore: ""
    property int countt2: 0
    Settings
        id:mysetting4
        property alias datastore: sampleapp.datastore
        property alias mycount: sampleapp.countt2
    
    FavModel
        id:dataModel
    
    Component.onCompleted: 
        console.log("onCompleted works right now.")
        if(datastore)
            dataModel.clear()
            var datamodel = JSON.parse(datastore)
            for (var i=0; i<datamodel.length; ++i) dataModel.append(datamodel[i])
        
    
    onCanGoBackChanged: 
        var datamodel=[]
        for (var i=0; i<dataModel.count; ++i) datamodel.push(dataModel.get(i))
        datamodel = JSON.stringify(datamodel)
        console.log("datastore: "+datastore)
    
    actions: [
        Action 
          id:favourite2
            onTriggered:
                countt2++
                console.log("Count/2: "+ countt2%2)
                if(countt2%2==1)
                    console.log("List must be added")
                    dataModel.append( "title": "Application Tools", "source": "qrc:/SampePage.qml" )
                
                else if(countt2%2==0)
                    console.log("List must be removed.")
                    return dataModel.remove(dataModel.index)
                
            
            icon.name: "toggle/star"
            toolTip: qsTr("Add/Remove")
        
    ]

*我无法在第二个示例中仅制作 Qt Quick Controls 2.0 示例,我必须使用流体 qml 库,因为制作列表菜单很简单。

【问题讨论】:

【参考方案1】:

在您的代码中,您有 2 个问题:

首先是你没有将列表保存在datastorage
[...]
datamodel = JSON.stringify(datamodel)
[...]

必须是:

datastore = JSON.stringify(datamodel)
第二个是你在错误的时间保存数据,页面加载后发生onCanGoBackChanged事件。一般的做法必须是在item加载完成时加载数据,在item被销毁之前保存数据,所以使用Component.onCompletedComponent.onDestruction事件比较合适。
Component.onCompleted: 
    console.log("onCompleted works right now.")
    if(datastore)
        dataModel.clear()
        var datamodel = JSON.parse(datastore)
        for (var i=0; i<datamodel.length; ++i) dataModel.append(datamodel[i])
    

Component.onDestruction: 
    console.log("onDestruction works right now.")
    var datamodel=[]
    for (var i=0; i<dataModel.count; ++i) datamodel.push(dataModel.get(i))
    datastore = JSON.stringify(datamodel)
    console.log("datastore: "+datastore)

另一个小错误,因为我认为这是一个测试代码。假设dataModel 中没有数据并且countt2 是偶数,那么您将要从dataModel 中删除不存在的数据。

更新:

Settings 用于存储数据并能够在关闭应用程序后恢复,但如果您想在多个文件之间共享数据,一个可能的解决方案是实现singleton,因为这是一个单独的元素存在于整个应用程序中。在任何地方都可以轻松修改。

为了构建单例,我们创建一个具有以下结构的 .qml 文件:

Shared.qml

pragma Singleton
import QtQuick 2.0

QtObject 
    property var favModel: FavModel

然后我们添加另一个名为 qmldir 的文件:

qmldir

singleton Shared 1.0 Shared.qml

然后我导入它,我们以如下方式使用它:

import "."

[...]

Shared.favModel.some_function()

例如在您的特定情况下:

ma​​in.qml

import QtQuick 2.6
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.3
import Fluid.Controls 1.0
import QtQuick.Window 2.3
import Qt.labs.settings 1.0
import "."

ApplicationWindow
    id:main
    width: 640
    height: 480
    visible:true
    title: "Example App"

    property string datastore: ""
    Settings
        property alias datastore: main.datastore
    

    Component.onCompleted: 
        console.log("onCompleted works right now.")
        if(datastore)
            Shared.favModel.clear()
            var datamodel = JSON.parse(datastore)
            for (var i=0; i<datamodel.length; ++i) Shared.favModel.append(datamodel[i])
        
    

    Component.onDestruction: 
        console.log("onDestruction works right now.")
        var datamodel=[]
        for (var i=0; i<Shared.favModel.count; ++i) datamodel.push(Shared.favModel.get(i))
        datastore = JSON.stringify(datamodel)
        console.log("datastore: "+datastore)
    
    [...]

SamplePage.qml

import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Controls.Material 2.2
import Fluid.Controls 1.0
import "."

Page
    title:qsTr("Page1")
    appBar.maxActionCount: 2
    id:sampleapp

    actions: [
        Action 
            id:favourite2
            onTriggered:
                Shared.favModel.append( "title": "Application Tools", "source": "qrc:/SamplePage.qml" )
            
            icon.name: "toggle/star"
            toolTip: qsTr("Add/Remove")
        
    ]

Favorites.qml

import QtQuick 2.6
import QtQuick.Controls 2.0
import QtQuick.Controls.Material 2.0
import Fluid.Controls 1.0

import "."

Tab
    title:"FAVORITES"
    id:favtab

    ListView 
        id:favorites
        width: parent.width
        height: parent.height
        focus: true
        interactive: true
        clip: true
        model: Shared.favModel
        delegate: ListItem 
            text: model.title
            onClicked: pageStack.push(model.source)
        
    

完整和更新的示例可以在以下link中找到

【讨论】:

非常感谢您抽出宝贵的时间。看到两个主要错误是有帮助的。实际上,我尝试将列表项添加到 Favourite.qml,而不是 SamplePage.qml。例如,我有 20 个页面,这些页面应该可以作为列表项添加到收藏夹标签页中。我找不到任何方法来连接收藏夹的列表模型以在其中添加列表项。你能启发一下吗? Here 是我尝试添加的一张图片。 @EdipAhmet 你想从 SamplePage.qml 中完成的事件中修改来自 Favorites.qml 的 FavModel 吗? Here 是 SamplePage,here 是 Favourites.qml 页面。我尝试通过单击星号操作将列表项添加到收藏标签页。我试过了,console.log 似乎可以工作,但它没有将列表项添加到收藏夹的列表模型中。是的,我尝试将列表项从 SamplePage.qml 动态添加到 Favorites.qml。 抱歉,Favorites.qml 是 here。 @EdipAhmet 我已经更新了我的答案和存储库的代码,试试看如果有问题告诉我。

以上是关于如何从另一个 QML 访问和控制 ListModel 的内容的主要内容,如果未能解决你的问题,请参考以下文章

QT QML - 从另一个类访问 qml 模型

如何从另一个 Qml 的 Qml 中的属性中获取值?

如何从另一个 QML 文件调用 QML 文件中定义的 Javascript 函数?

如何在 Cascades、Blackberry 10 中使用 Qt/QML/C++ 从另一个 qml 文件中更改一个 qml 文件中的标签文本?

如何从另一个线程的 cpp 代码同步调用 qml 信号处理程序?

从另一个 QML 文件打开新的 QML 文件