QML StackView:项目在弹出时被销毁

QML StackView: Item Destroyed on pop

考虑以下示例:

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2

Window {
    visible: true
    width: 320
    height: 320

    StackView {
        id: stackView
        anchors.fill: parent
        Component.onCompleted: {
            stackView.push( { item: comp1, destroyOnPop:false } )
        }
    }

    Component {
        id: comp1
        Rectangle {
            color: "lightgray"

            Text {
                id: mtext
                anchors.centerIn: parent
                text: "First Page"
            }
        }
    }

    Component {
        id: comp2
        Rectangle {
            color: "lightgreen"

            Text {
                id: mtext
                anchors.centerIn: parent
                text: "Second Page"
            }

            MouseArea {
                id: mouseArea
                anchors.fill: parent
                onClicked: mtext.text += " Clicked"
            }
        }
    }

    Row {
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        Button {
            id: next
            text: "Next"
            onClicked: {
                stackView.push( { item: comp2, destroyOnPop:false } )
                enabled = false
                prev.enabled = true
            }
        }

        Button {
            id: prev
            text: "Prev"
            enabled: false
            onClicked: {
                stackView.pop()
                enabled = false
                next.enabled = true
            }
        }
    }
}

在这里,我在每次单击按钮时将 2 Component 推入 StackView,即单击 "Next" 按钮会加载第二页。当我单击它时,它会显示更新的文本 ("Second Page Clicked")。然后单击 "Prev" 按预期加载第一页。

现在,如果我再次单击 "Next",它应该加载带有更新文本 ("Second Page Clicked") 的第二页,但它没有。它显示初始文本 ("Second Page")。

所以问题是 Item 是否在弹出时被销毁?如果不是,那么第二页不应该显示更新后的文本吗 ("Second Page Clicked")?

我什至将标志 destroyOnPop 设置为 false。我是否误解了 StackView 的概念?有什么办法可以解决这个问题吗?

我想从 StackView 中的任何点加载任何页面,并且 Item 的状态与我离开时的状态相同。就像QStackWidget,这里我们用setCurrentIndex().

文档指的是 Item 对象,而您使用的是 Componentdocumentation 非常清楚一个组件 不是 Item 的事实,因为它不是从 Item 派生的。事实上,Component 就像 Class 一样,它被实例化到一个特定的对象。

每次打电话

stackView.push( { item: comp2, destroyOnPop:false } )

生成了组件 comp2 的一个新 "instance" 并且使用了这样的 new 实例而不是前一个实例。我强烈建议阅读 this article 以更好地理解 Component 对象和生成的实例之间的相关性。

可以通过createObject函数生成实例。因此,您可以创建一个 Item 数组,并使用 Item 代替 Component。最终代码如下所示:

import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2

Window {
    visible: true
    width: 320
    height: 320

    StackView {
        id: stackView
        anchors.fill: parent
        Component.onCompleted: {
            push( { item: items[0], destroyOnPop:false })
        }
        property variant items: [comp1.createObject(), comp2.createObject()]  // objects from the components
    }

    Component {
        id: comp1
        Rectangle {
            color: "lightgray"

            Text {
                id: mtext
                anchors.centerIn: parent
                text: "First Page"
            }
        }
    }

    Component {
        id: comp2
        Rectangle {
            color: "lightgreen"

            Text {
                id: mtext
                anchors.centerIn: parent
                text: "Second Page"
            }

            MouseArea {
                id: mouseArea
                anchors.fill: parent
                onClicked: mtext.text += " Clicked"
            }
        }
    }

    Row {
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        Button {
            id: next
            text: "Next"
            onClicked: {
                stackView.push({ item: stackView.items[1], destroyOnPop:false })
                enabled = false
                prev.enabled = true
            }
        }

        Button {
            id: prev
            text: "Prev"
            enabled: false
            onClicked: {
                stackView.pop()
                enabled = false
                next.enabled = true
            }
        }
    }
}

通过直接定义源中的 Rectagle 对象可以获得相同的正确结果。在这种情况下,我们有两个 Item 重新设置为 Window,感谢 destroyOnPop 设置为 false。

Rectangle {
    id: comp1
    color: "lightgray"
    visible: false

    Text {
        id: mtext
        anchors.centerIn: parent
        text: "First Page"
    }
}

Rectangle {
   id: comp2
   color: "lightgreen"
   visible: false

   Text {
        id: mtext2
        anchors.centerIn: parent
        text: "Second Page"
   }

   MouseArea {
       id: mouseArea
       anchors.fill: parent
       onClicked: mtext2.text += " Clicked"
   }
}