Qt QML ListView方法positionViewAtEnd()的作用正好相反

Qt QML ListView方法positionViewAtEnd()的作用正好相反,qt,listview,qml,qt5.3,Qt,Listview,Qml,Qt5.3,我快疯了。我在ScrollView中有一个ListView,与继承QabStretchListModel的模型连接。将对象添加到模型时,ListView将使用委托显示这些对象。到目前为止,一切顺利 但我真的希望视图保持滚动到底部(就像聊天窗口),我很难做到这一点。以下是相关的QML代码: Rectangle { ScrollView { [anchor stuff] ListView { id: messageList

我快疯了。我在ScrollView中有一个ListView,与继承QabStretchListModel的模型连接。将对象添加到模型时,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()
            }
        }
    }
}
文本“此打印正确”打印,为什么不定位?事实上,它似乎将位置重置为顶部。因此,我尝试了
位置视图开始()
,但效果相同

我完全被难住了。这感觉像一个bug。

中有一个注释:

注意:方法只能在组件完成后调用。要在启动时定位视图,Component.onCompleted应调用此方法

将您的
ListView.onAdd:
更改为

Component.onCompleted: {
    console.log("This prints just fine!")
    messageList.positionViewAtEnd()
}
而且效果很好


在您的情况下,ListView在创建和完成新委托之前发出
add
信号。ListView仍在幕后处理某些内容,因此
positionViewAtEnd
无法按预期工作。而且,
/*这很有效*/因为它是在新委托完成后调用的。但是,不要认为这总是有效的。只需按照说明,在文档中的
组件中调用
positionViewAtEnd
。onCompleted

您还需要设置
当前索引

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++)})
        }
    }
}

仍然会有一些跳到第一个元素,然后再跳下来几秒钟。

你是对的。非常感谢。对于未来的谷歌用户来说,第二个重要部分是
组件.onCompleted
必须出现在代理中,而不是列表本身。我错过了。嗯……你说得对。当您滚动列表时,ListView确实会创建新代理,而我的回答失败。也许您可以在调用
positionViewAtEnd
之前检查模型中的元素数量,但我认为这不是一个好的解决方案。不清楚为什么/是否Qt开发人员真的打算将
完成的
附加到委托上。似乎我们缺少了
positionViewAtEnd
的预期用途。现在,我将撤消接受此答案。
组件.onCompleted
信号可用于所有QML组件,例如您的
矩形
。无论在何处创建了
矩形
,在静态QML代码中或在委托中按需创建,它都可用。
positionviewated
的文档可能有点误导。他们说的是:当列表被完全创建时,向下滚动(每个列表一次,启动时)。你的注释掉的解决方案有什么问题?这对我在Ubuntu上使用Qt5.4是有效的(从我所看到的情况来看,它位于末尾,而不是计数-2)。请为滚动和onCountChanged不工作时发生的挂起创建错误报告。问题是该项目没有立即添加到列表中(实际项目是从服务器请求添加的),因此它要么被一个(在发件人上)关闭,要么根本不更新(在另一个客户端上)。
positionViewatStart()
必须对正在更新的列表本身起作用。我提交了一个错误请求(QTBUG-41571),所以我希望这篇文章足以澄清这个问题。你解决了这个问题吗?我有确切的问题,我找不到任何解决办法。谢谢!不幸的是,没有。我最终通过重新设计GUI解决了这个问题。我希望这个问题能在5.5中解决,但我还没有检查。如果你明白了,回来吧!:)有趣。也许这就是Qt中错误的来源。谢谢你节省了我的时间。
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++)})
        }
    }
}