Qt/QML:在加载程序加载后访问 ListView 以跳转到特定项目/页面
Posted
技术标签:
【中文标题】Qt/QML:在加载程序加载后访问 ListView 以跳转到特定项目/页面【英文标题】:Qt/QML: Accessing a ListView after a Loader has loaded it to jump to a specific item/page 【发布时间】:2015-06-09 09:15:23 【问题描述】:我有一个 QML 应用程序,它基本上只是一个 ListView,它显示许多“章节”,而每个章节又包含一个或多个“页面”。
由于我不知道 QML 在生产中可能有多少章节和页面,我使用 Loader
按需加载页面,这样可以节省一些内存。
所以问题是我想按一个按钮“跳转”到某个故事和页面。我在示例中添加了一些按钮,它们已经跳转到不同的章节。
您可以在章节之间垂直滑动,也可以在每章的页面之间水平滑动。
我遇到的问题是,在切换/加载特定章节后,我无法弄清楚如何让包含页面的ListView
跳转到特定页面。基本上我错过了pagesView.currentPage = 5
或类似的东西。
什么是让它工作的好方法?
对应的 QML。您可以使用 qmlscene 运行它。
import QtQuick 2.4
import QtQuick.Controls 1.2
ApplicationWindow
width: 1024
height: 768
Component
id: pageViewComponent
ListView
id: pagesView
property int storyIndex: chapterView.modelData
orientation: ListView.Horizontal; clip: true
model: 20; snapMode: ListView.SnapToItem
delegate: Rectangle
width: pagesView.width; height: pagesView.height
color: Qt.rgba(Math.random(),Math.random(),Math.random(),1)
border.color: "black"
Text text: "Page " + modelData; anchors.centerIn: parent; color: "white"
Rectangle
color: "black"
anchors.fill: parent
// Chapters
ListView
id: chapterView
model: 8
anchors.fill: parent
snapMode: ListView.SnapToItem
delegate: Rectangle
color: Qt.rgba(Math.random(),Math.random(),Math.random(),1)
width: chapterView.width; height: chapterView.height
Rectangle
width: parent.width * 0.6; height: parent.height * 0.6
anchors.centerIn: parent
Loader
anchors.fill: parent
sourceComponent: pageViewComponent
Text
x: 50; y: 50
color: "white"; font.pointSize: 30
text: "Chapter " + modelData
Flow
Button
text: "Go to Chapter 2, Page 7"
onClicked:
chapterView.positionViewAtIndex(2, ListView.Beginning)
//
//
// After jumping to the correct chapter, we obviously have to jump
// to the correct page after the Loader for that specific chapter has
// completed loading the pages of the chapter.
//
//
Button
text: "Go to Chapter 1, Page 1"
onClicked:
chapterView.positionViewAtIndex(1, ListView.Beginning)
// dito
Button
text: "Go to Chapter 5, Page 2"
onClicked:
chapterView.positionViewAtIndex(5, ListView.Beginning)
// dito
【问题讨论】:
使用Loader.item访问动态创建的pagesView
。所以你可以idOfTheLoader.item.positionViewAtIndex(7, ListView.Beginning)
换页。
@mcchu - 这将访问当前项目的加载器,而不是您要访问的加载器。另外,对它的调用必须安排在加载其内容时运行,并带有 lambda 和参数捕获。
【参考方案1】:
可能是这样的吗?
// go to chapter 2 page 7
chapterView.positionViewAtIndex(2, ListView.Beginning)
var loader = chapterView.currentItem.loader
loader.loaded.connect(function(l, p)
return function()
l.item.positionViewAtIndex(p, ListView.Beginning)
(loader, 7))
这样,当加载器加载项目时,将调用访问项目的函数。
同时公开加载器以便可以访问它:
Rectangle
//...
property Loader loader : l
Loader
id: l
// ...
【讨论】:
【参考方案2】:这是我的做法:
在pagesView
中定义属性,使其能够更新其外观和状态:
Component
id: pageViewComponent
ListView
id: pagesView
// Begin inserted code
property int chapterIndex: -1
property ListView chapterView: null
Connections
target: chapterView
onSelectedPageChanged:
if (chapterIndex === chapterView.selectedChapter)
pagesView.positionViewAtIndex(chapterView.selectedPage, ListView.Beginning)
onChapterIndexChanged:
if (chapterView && chapterIndex === chapterView.selectedChapter)
pagesView.positionViewAtIndex(chapterView.selectedPage, ListView.Beginning)
// End inserted code
orientation: ListView.Horizontal; clip: true
model: 20; snapMode: ListView.SnapToItem
delegate: Rectangle
width: pagesView.width; height: pagesView.height
color: Qt.rgba(Math.random(),Math.random(),Math.random(),1)
border.color: "black"
Text text: "Page " + modelData; anchors.centerIn: parent; color: "white"
定义将存储整个事物状态(即当前章节和页面)的属性:
property int selectedChapter: 0
property int selectedPage: 0
根据selectedChapter
属性更新***ListView位置:
onSelectedChapterChanged: positionViewAtIndex(selectedChapter, ListView.Beginning)
在创建 pagesView
时设置其属性:
Loader
id: pagesViewLoader
anchors.fill: parent
sourceComponent: pageViewComponent
onLoaded:
item.chapterIndex = Qt.binding(function() return modelData )
item.chapterView = chapterView
从Button
触发章节和页面更改:
// Define method in top-level ListView
ListView
id: chapterView
function goTo(chapter, page)
selectedChapter = chapter
selectedPage = page
// ...
// Call method from onClicked handler
Button
text: "Go to Chapter 2, Page 7"
onClicked:
chapterView.goTo(/* chapter */ 2, /* page */ 7)
重要提示
注 1
在第 4 步中,modelData
没有直接设置,而是被包装到 Qt.binding
函数调用中。这就是你从 javascript 绑定到值的方式。这是必要的,因为 ListView 重用了它的委托实例,并且 pagesView
实例可以在单个 onLoaded
消息之后以不同的 modelData
值重用。
注2
起初我在onClicked
中使用了两个属性赋值,而没有将它们包装在goTo
函数中:
chapterView.selectedChapter = chapter
chapterView.selectedPage = page
但这导致第二行出现错误 (chapterView is not defined
)。当第一行执行时,chapterView
滚动到选定的章节,并且当前的委托项目从场景中移除,因为它不再需要。我不知道这个“从场景中移除”在技术上是如何完成的,但结果是在第一行之后chapterView
不再定义。因此需要将这两个赋值封装在一个函数调用中。
【讨论】:
不错的答案。我会试一试,然后回复你!如果您习惯于使用传统工具开发应用程序,QML 有时可能有点难以理解。 ;) 更新:从我所看到的情况来看。我从你的回答中学到了一些对我未来有帮助的东西:1)Qt.binding()——我怎么会错过这个? 2) 在 QML 对象中自定义function
s。谢谢!
为了完整起见,我用一个工作示例来说明这个要点:gist.github.com/bastibense/7f949e2f791b4db27c6f以上是关于Qt/QML:在加载程序加载后访问 ListView 以跳转到特定项目/页面的主要内容,如果未能解决你的问题,请参考以下文章