jmb*_*eck 16 qt listview qml qt5.3
我要疯了.我在ScrollView中有一个ListView,连接到一个继承QAbstractListModel的模型.将对象添加到模型时,ListView使用委托显示它们.到现在为止还挺好.
但我真的希望视图保持滚动到底部(就像聊天窗口一样),而且我很难实现这一点.这是相关的QML代码:
Rectangle {
ScrollView {
[anchor stuff]
ListView {
id: messageList
model: textMessageFiltered
delegate: messageDelegate
}
}
TextField {
id: messageEditor
[anchor stuff]
onAccepted: {
controller.sendTextMessage(text)
text = ""
/* This works. */
//messageList.positionViewAtEnd();
}
}
Component {
id: messageDelegate
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
color: "white"
height: nameText.height + 4
Text {
id: nameText
wrapMode: Text.Wrap
text: "<b>" + authorName + " (" + authorId + ")</b> " + message
[anchor stuff]
}
ListView.onAdd: {
console.log("This prints just fine!")
messageList.positionViewAtEnd()
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
真正奇怪的是,messageList.positionViewAtEnd()(在文件的末尾)实际上将它跳到了开头.如果没有调用,视图将保持原样,即使列表中出现新条目也是如此.事实上,如果您查看ListView.positionViewAtEnd()的Qt文档,它会说:
将视图定位在开头或结尾,同时考虑到......
这是文档中的愚蠢错误,还是什么?我已经尝试了所有我能想到的工作,特别是positionViewAtIndex()方法和使用荧光笔强制滚动发生.但没有任何作用.请注意/* This works. */上面源代码中的注释.当启用它时,它完全正常!(当然,它跳转到ListView.count() - 2索引,而不是列表的末尾)
有谁知道这里可能有什么问题?我可以尝试证明QML中有一个可怕的,可怕的错误的任何例子?
我正在使用Qt 5.3.1和QtQuick 2.0(或2.1或2.2也失败).我已经尝试了很多很多其他配置和代码,所以请询问您是否需要更多信息.我已经完全用尽了谷歌.
谢谢!
编辑1
虽然接受的答案确实解决了上述问题,但它涉及向Component.onCompleted委托添加.当您滚动列表时,这似乎会导致问题,因为(我相信)向上滚动时会将代理添加到视图中,从而导致调用onCompleted触发器,即使模型项不是新项也是如此.这是非常不受欢迎的.实际上,当我尝试向上滚动然后将新元素添加到列表时,应用程序会冻结.
看起来我需要一个model.onAdd()信号,而不是使用委托实例的存在来触发滚动.有任何想法吗?
编辑2
这怎么不行?
ListView {
id: messageList
model: textMessageFiltered
delegate: messageDelegate
onCountChanged: {
console.log("This prints properly.")
messageList.positionViewAtEnd()
}
}
Run Code Online (Sandbox Code Playgroud)
文本"打印正确"打印,所以为什么不定位?实际上,它似乎将位置重置为顶部.所以我尝试了positionViewAtBeginning(),但那做了同样的事情.
我完全难过了.感觉就像一个bug.
你也需要设置它currentIndex.
testme.qml
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Window 2.0
ApplicationWindow {
title: qsTr("Hello World")
width: 300
height: 240
ScrollView {
anchors.fill: parent
ListView {
anchors.fill: parent
id: messageList
model: messageModel
delegate: Text { text: mytextrole }
highlight: Rectangle { color: "red" }
highlightMoveDuration: 0
onCountChanged: {
var newIndex = count - 1 // last index
positionViewAtEnd()
currentIndex = newIndex
}
}
}
ListModel {
id: messageModel
ListElement { mytextrole: "Dog"; }
ListElement { mytextrole: "Cat"; }
}
Timer {
property int counter: 0
running: true
interval: 500
repeat: true
onTriggered: {
messageModel.append({"mytextrole": "Line" + (counter++)})
}
}
}
Run Code Online (Sandbox Code Playgroud)
还有一些跳到第一个元素并跳回来几分之一秒.
文档中有一个注释:
注意:只应在Component完成后调用方法.要在启动时定位视图,应该通过Component.onCompleted调用此方法.
改变你ListView.onAdd:的
Component.onCompleted: {
console.log("This prints just fine!")
messageList.positionViewAtEnd()
}
Run Code Online (Sandbox Code Playgroud)
它运作良好.
在您的情况下,ListView add在创建和完成新委托之前发出信号.ListView仍在处理场景背后的某些事情,因此positionViewAtEnd无法按预期工作.而且/* This works. */由于新的委托完成后,它被调用.但是,不要认为这总是有效.只需按照说明,称positionViewAtEnd在Component.onCompleted,在文档中.