QML 绑定变量不同于委托中的本地副本 - 有时

QML bound variable differs from local copy in delegate - sometimes

在表格视图中单击 header 时出现奇怪的问题。我正在尝试通过单击列 header 来制作排序和反转排序方向的列。经过大量追踪,我发现有时当我单击 ColumnHeader 时,它似乎 运行 来自不同 ColumnHeader 的 onClick 代码。就好像代表是 reusing/running 一个不同的实例。只有当我在 onClick 事件中调用 mysort 函数(除了调用祖先的 Qt 排序函数之外什么都不做)时才会出现此问题。

为了澄清,我打印出绑定到委托中的列 'index' 的 'columnNum' 和 'copyColumnNum' 当我的 header 被创建。每当我单击 header 列时,我都会打印出这两个值,它们应该始终相同。一些 运行s 它们是,其他时候每次点击的值都不同。这证实了有时 onClick 代码 运行ning 在与我期望的不同的实例中。

为什么? copyColumnNum 与 columnNum 有何不同?我一定是遗漏了一些关于绑定/委托的基本知识。

在main.qml

HorizontalHeaderView {
    anchors.top: parent.top
    anchors.left: parent.left
    anchors.right: parent.right
    id: myHorizontalHeaderView
    syncView: myTableView


    delegate: ColumnHeader {
        label: model.display
        columnNum: index
    }
}

在ColumnHeader.qml

import QtQuick 2.0
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15

Button {
    property string label // Bound to model's display role for this column
    property int columnNum  // Bound to column index
    property int sortOrder : 0
    property int copyColumnNum;

    Component.onCompleted: {
        copyColumnNum = columnNum;
    }

    Rectangle {
        anchors.fill: parent
        Item {
            Text {
                id: labelText
                text: label
                color: "white"
                anchors.verticalCenter: parent.verticalCenter
            }
    }

    onClicked: {
        console.log("Clicked on copyColumnNum "+copyColumnNum+" columnNum is "+columnNum);
        if (sortOrder === 1)
           sortOrder = 0;
        else
           sortOrder = 1;
        tableSortFilterProxyModel.mySort(copyColumnNum, sortOrder);
        sortingColumn = copyColumnNum;
    }
}

这不是一个有约束力的问题 - 这是一个委托问题。在 TableView(Horizo​​ntalHeaderView 继承自)及其委托 属性:

上查看这里的警告

https://doc.qt.io/qt-5/qml-qtquick-tableview.html#delegate-prop

Note: Delegates are instantiated as needed and may be destroyed at any time. They are also reused if the reuseItems property is set to true. You should therefore avoid storing state information in the delegates.

大多数(如果不是全部)*视图创建一个委托池,可以在当前项目视图中看到这些内容,然后在您滚动时返回并从池中重新发出。换句话说,当列(委托)在视图的一端离开视图时,随着新列进入视图,它会被移动并放置在视图的另一端。除了滚动之外,还有其他情况也可能导致这种情况(插入、删除、排序等)。

这就是问题的来源。您不应在委托本身中存储任何状态,因为现有状态将在您滚动时在新列中重复使用,而无需干预 destroy/create.

通常,此限制是通过在模型中存储所有状态来管理的。或者在这种情况下,您可能可以使用 TableView 公开的现有索引、行和列属性(在上面链接的委托 属性 文档中也提到了)。

更多关于 TableView 如何重用项目的讨论:

https://doc.qt.io/qt-5/qml-qtquick-tableview.html#reusing-items

如此处所述,您还可以通过捕获 TableView::reused 信号来管理此问题:

Note: Avoid storing any state inside a delegate. If you do, reset it manually on receiving the TableView::reused signal.