如何从另一个 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 访问、保存和恢复列表模型的内容?谢谢。
第一个例子:
main.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
第二个例子:
main.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.onCompleted
和Component.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()
例如在您的特定情况下:
main.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 的内容的主要内容,如果未能解决你的问题,请参考以下文章
如何从另一个 QML 文件调用 QML 文件中定义的 Javascript 函数?
如何在 Cascades、Blackberry 10 中使用 Qt/QML/C++ 从另一个 qml 文件中更改一个 qml 文件中的标签文本?