QML StackView:三种入栈方式(Item、Component 与 URL)

stack.push(参数) 里那个参数到底能传什么?

官方文档说它可以是一个 Item、一个 Component 或一个 url------三种传法对应三种典型的页面管理方式。

这篇用一个 demo 把三种 push 各做一遍,它们推入的都是同一个 PushItem.qml 页面,但加载路径完全不同:一种是"页面对象已在 QML 里声明好,直接推实例",另两种是"把页面当模板,用时再创建"。顺带看 push 返回的页面对象怎么用------返回后立刻 connect 它发出的信号,实现页面与栈的解耦回调。

  • Push Item --- push 一个已存在的页面实例
  • Push Component --- Qt.createComponent() 创建组件后 push
  • Push URL --- push 一个 QML 文件地址,内部自动加载

三种 push 方式

页面顶部三个按钮,分别演示 push 一个 Item、push 一个 Component、push 一个 URL。被推入的页面是同一个 PushItem.qml:白底圆角卡片,中间一行标题(颜色随 push 传入的参数变化)、一段说明文字和一个 Pop 按钮。点 Pop 会通知外层把这一页弹掉。

演示代码

qml 复制代码
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts

FadeInAnimation {
    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20
        spacing: 15

        // ... 省略标题组件 TitleSeparator ...

        StackView {
            id: stack
            initialItem: mainView
            Layout.fillWidth: true
            Layout.fillHeight: true
            spacing: 15
            clip: true
        }
    }

    Component {
        id: mainView

        ColumnLayout {
            spacing: 10

            property color textColor: "#333"

            Button {
                text: "Push Item"
                Layout.fillWidth: true
                Layout.preferredHeight: 30
                onClicked: {
                    var info = {"textColor":"#3498db", "textTitle":"Push Item", "textInfo":"用于测试【Push Item】, 调用StackView - push" }
                    var page = stack.push(stackItem, info)
                    page.popClicked.connect(slotPopItem)
                }
            }

            Button {
                text: "Push Component"
                Layout.fillWidth: true
                Layout.preferredHeight: 30
                onClicked: {
                    var info = {"textColor":"#e74c3c", "textTitle":"Push Component", "textInfo":"用于测试【Component】, 调用Qt.createComponent()" }
                    var com = Qt.createComponent(Qt.resolvedUrl("PushItem.qml"))
                    if (com.status === Component.Ready) {
                        var page = stack.push(com, info)
                        page.popClicked.connect(slotPopItem)
                    }
                }
            }

            Button {
                text: "Push URL"
                Layout.fillWidth: true
                Layout.preferredHeight: 30
                onClicked: {
                    // 通过 URL 加载 PushItem.qml
                    var info = {"textColor":"#2ecc71", "textTitle":"Push URL", "textInfo":"用于测试【Push URL】- Qt.resolvedUrl" }
                    var page = stack.push(Qt.resolvedUrl("PushItem.qml"), info)
                    page.popClicked.connect(slotPopItem)
                }
            }

            Item { Layout.fillHeight: true }
        }
    }

    PushItem {
        id: stackItem
        visible: false
    }

    function slotPopItem() {
        stack.pop()
    }
}

被推入的页面 PushItem.qml

qml 复制代码
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls

Rectangle {
    width: 250
    height: 250
    border.color: "#ccc"
    border.width: 0
    radius: 6
    visible: false

    property color textColor: "#333"
    property string textTitle: ""
    property string textInfo: ""
    signal popClicked

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 0
        spacing: 15

        Text {
            text: textTitle
            color: textColor
            font.pointSize: 13
            font.bold: true
        }

        Text {
            text: textInfo
            color: textColor
            font.pointSize: 11
            Layout.fillWidth: true
            Layout.preferredHeight: 60
            wrapMode: Text.Wrap
        }

        RoundButton {
            text: "Pop"
            Layout.preferredWidth: 90
            Layout.preferredHeight: 30
            onClicked: popClicked()
        }

        Item { Layout.fillHeight: true }
    }
}

关键逻辑解析

push 的第二个参数 properties 会把值注入页面同名属性 。三个按钮都构造了一个 info 对象,键名是 textColortextTitletextInfo,而 PushItem 恰好声明了这三个 property。push 时传入的 properties 会按名赋给新页面------这就是为什么三种方式推入同一个 qml,标题文字和颜色却各不相同。属性注入让"同一页面模板 + 不同数据"的复用模式成立。

Push Item:直接推一个已存在的实例PushItem { id: stackItem; visible: false } 挂在文件根部但平时不可见,像一个"备用页面"。stack.push(stackItem, info) 把这个现成实例推入栈。适合页面对象已经声明好、需要重复使用同一份实例的场景------但要小心:它一直被复用的是同一个实例,适合"推入一次用完就弹"的页面,不适合需要同时存在多份副本的场景。

Push Component:先用 Qt.createComponent 造出组件Qt.createComponent(Qt.resolvedUrl("PushItem.qml")) 把 qml 文件编译成一个 Component 对象,组件就绪后 push 它------StackView 会为每次 push 创建一份页面实例。本地文件通常同步加载完成,但加载远程组件或文件较多时可能未就绪,所以稳妥起见先查 com.status === Component.Ready 再 push(这是 createComponent 用法的标准姿势,避免拿一个没加载好的组件去 push)。适用于"页面文件可能较多、想统一管理加载时机"的场景。

Push URL:把地址直接交给 StackViewstack.push(Qt.resolvedUrl("PushItem.qml"), info) 不用自己创建组件,StackView 内部完成加载和实例化,代码最省。三种方式最终都会返回"成为当前页的那个 Item",所以 var page = stack.push(...) 拿到的就是新页面对象。

page.popClicked.connect(slotPopItem) 是页面与栈解耦的关键 。PushItem 内部只声明 signal popClicked,Pop 按钮点了就发信号------它并不知道 StackView 的存在,也不知道自己该被谁弹掉。外层拿到 push 返回的 page 后,把它的 popClicked 信号连到 slotPopItem,后者执行 stack.pop()。这样页面文件可独立复用(放哪个 StackView 里都能用),栈操作统一由外层负责。

enabled 与状态保护:这里没给按钮加 enabled 判断,因为每次 push 后当前页会被新页面盖住,按钮点不到,天然防止重复触发。

三种方式怎么选

方式 加载时机 页面实例 适用场景
Push Item 页面已创建好,随用随推 复用同一个实例 单份常驻页面、动态数据
Push Component 手动 Qt.createComponent,可控制加载 每次 push 新建 需要管理加载状态、批量页面
Push URL StackView 内部自动加载 每次 push 新建 最省代码,页面独立成文件

日常开发里 Push URL 最常用------页面天然按文件拆分,push 时给个地址即可;需要先确认组件加载成功再动作时用 Component;页面对象已在界面里声明、只需要推一次的场景才用 Item。

运行验证

  1. Qt Creator 打开 qml_stackview/CMakeLists.txt,按 Ctrl+R 运行;
  2. 左侧点「Push对象」,依次点 Push Item / Push Component / Push URL;
  3. 观察每次推入的卡片标题与颜色不同(蓝/红/绿),点卡片上的 Pop 按钮,页面被外层 slotPopItem 弹回按钮页。

扩展复用方向

  • properties 注入不止传文本颜色,传数据对象、回调函数都能按名赋到页面属性上,做成"通用详情页 + 数据驱动";
  • 把 push 返回的 page 存起来,connect 它的多个信号,就能实现页面内确认框、表单提交后外层统一收尾的协作模式;
  • 页面文件多了以后,把 URL 字符串集中到一个路由表(按页面名查 URL),push 时只传名字,页面跳转逻辑更清晰。

已验证环境

相关推荐
Quz2 小时前
QML StackView:入栈、出栈、替换与批量操作
qt
老赵的博客4 小时前
c++面试之从虚函数表到Rtti一次性讲清楚
c++·qt
颜颜yan_9 小时前
Git Cola 鸿蒙 PC 版适配全记录:从 Qt 桌面工具到 ArkTS 原生应用
git·qt·harmonyos
Lsir10110_10 小时前
从按钮“点不动“讲起——深入理解 Qt 信号槽机制
开发语言·qt·信号处理
lqj_本人10 小时前
WinMerge 鸿蒙 PC 适配全记录:以 Qt 重建桌面外壳,打通文件与文件夹差异闭环
qt·华为·harmonyos
lqj_本人10 小时前
Tftpd64 鸿蒙 PC 适配全记录:用 Qt 重建一组可运行的 UDP 网络服务
qt·udp·harmonyos
User_芊芊君子11 小时前
RStudio 鸿蒙 PC 适配全记录:以 Qt 原生工作区承载嵌入式 R
qt·r语言·harmonyos
颜颜yan_12 小时前
Firebird 鸿蒙 PC 适配全记录:打通数据库内核、Qt 管理端与原生维护工具
数据库·qt·harmonyos
鸽芷咕13 小时前
Mu Editor 鸿蒙 PC 适配全记录:用 Qt 与嵌入式 CPython 重建教学型 Python IDE
python·qt·harmonyos