QML学习笔记(四十)QML的ApplicationWindow和StackView

前言

ApplicationWindow是一个已经具备基础ui的窗口,和Window同样都是顶层窗口,如果希望实现标题栏、菜单栏这种快速开发的导航功能的话可以选择它。

StackView是一种可以将任意QML页面进行堆栈压入的多层显示窗口,适用于需要进行翻页等操作的场景。

一、ApplicationWindow

ApplicationWindow 是 QtQuick.Controls 2 给你的"成品主窗口"------自带标题栏、菜单栏、工具栏、状态栏、键盘焦点链、平台窗口生命周期信号,不需要再包一层 Window,直接当根节点用。

ApplicationWindow是一个窗口,可以方便地在窗口中添加菜单栏、页眉和页脚项。

您可以将ApplicationWindow声明为应用程序的根项,并使用QQmlApplicationEngine运行它。通过这种方式,您可以从QML控制窗口的属性、外观和布局。

二、StackView

StackView = QML 的"页面导航栈"

  • 一条指令 push(item) 把任意 QML 页面压栈,自动动画切换
  • pop() 出栈回退,深度任意
  • 自带生命周期:页面可动态创建/销毁,也可缓存
  • 有信号 currentItemChanged / depthChanged 监听导航
  • 支持滑动、淡入淡出等过渡动画,也能自定义

一句话:
"QML 世界的 QStackedWidget + 历史栈 + 动画 三合一。"

它和QWidget中的QStackedWidegt属于同一个概念的产物都是用于进行翻页操作的。这里给出它们的总结对比:

维度 QML StackView QWidget QStackedWidget
底层类型 QQuickItem(场景图节点) QWidget(经典窗体)
使用语言 QML + JS C++ / QtWidgets
页面内容 任意 QML 组件(矩形、列表、复杂 UI) 任意 QWidget(按钮、表格、自定义窗体)
切换方式 命令式 push(item) / pop() / replace() 支持动画、传参、回退栈 索引式 setCurrentIndex(int)setCurrentWidget(QWidget*) 无内建动画、无栈概念
动画 内置滑动、淡入淡出等,可自定义 (需自己写 QPropertyAnimation
生命周期 自动创建/销毁(可缓存) 所有页面一次性构造,只隐藏不销毁(除非手动删除)
导航栈 真正的"后进先出"栈,可多级回退 仅当前索引,没有历史栈
信号 currentItemChanged / depthChanged / pushCompleted currentChanged(int)
性能 动态实例化,内存占用小 一次性构造,切换快但初始慢
平台限制 Qt Quick 场景 经典 Widget 场景

三、测试例子

代码:

cpp 复制代码
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Window 2.14
import QtQuick.Layouts 1.12

ApplicationWindow {
    id: mainWindow
    visible: true
    width: 480
    height: 320
    title: qsTr("QmlApplicationWindow")
    color: "#f5f5f5"                     // 客户区背景

    /* 1. 菜单栏 */
    menuBar: MenuBar {
        Menu {
            title: qsTr("文件")
            MenuItem { text: qsTr("打开"); onTriggered: console.log("打开") }
            MenuItem { text: qsTr("退出"); onTriggered: Qt.quit() }
        }
        Menu {
            title: qsTr("帮助")
            MenuItem { text: qsTr("关于"); onTriggered: console.log("关于") }
        }
        MenuSeparator{
            height: 2
        }
        Menu {
            title: qsTr("New")
            Action{
                id: newActionId
                text: "New"
//                icon.source: ""
                onTriggered: console.log("New")
            }
            Action{
                id: saveActionId
                text: "Save"
//                icon.source: ""
                onTriggered: console.log("Save")
            }
        }
    }

    /* 2. 工具栏 */
    header/*toolBar*/: ToolBar {
        RowLayout {
            anchors.fill: parent
            ToolButton { action: newActionId }
            ToolButton { action: saveActionId }
            Item { Layout.fillWidth: true }   // 弹簧
            Label { text: "简易工具栏" }
        }
    }

    /* 3. 客户区内容 */
    StackView{
        id: stackId
        anchors.fill: parent
        initialItem: Rectangle{ color: "grey" }
    }

    footer: TabBar{
        id: tabBarId
        width: parent.width

        TabButton{
            text: "Red"
            onClicked: function(){
                stackId.pop()
                stackId.push(redRect)
                console.log("Numbers of stack items: " + stackId.depth)
            }
        }

        TabButton{
            text: "Green"
            onClicked: function(){
                stackId.pop()
                stackId.push(greenRect)
                console.log("Numbers of stack items: " + stackId.depth)
            }
        }

        TabButton{
            text: "Blue"
            onClicked: function(){
                stackId.pop()
                stackId.push(Qt.createQmlObject('import QtQuick 2.14; Rectangle {color: "blue"}', stackId))
                console.log("Numbers of stack items: " + stackId.depth)
            }
        }

        TabButton{
            text: "Orange"
            onClicked: function(){
                stackId.pop()
                stackId.push("Orange.qml")
                console.log("Numbers of stack items: " + stackId.depth)
            }
        }

        TabButton{
            text: "Pop"
            onClicked: function(){
                stackId.pop()
                console.log("Numbers of stack items: " + stackId.depth)
            }
        }
    }


    /* 4. 关闭前确认 */
    onClosing: function(closeEvent) {
        closeEvent.accepted = false;          // 先阻止
        console.log("用户点 × 了,可弹窗确认");
        // 这里写弹窗逻辑,若确认再 Qt.quit()
    }


    /* ① 内联 Component */
    Component {
        id: redRect
        Rectangle { color: "red" }
    }
    Component {
        id: greenRect
        Rectangle { color: "green" }
    }
}

运行效果:

1.最上面的是菜单栏menuBar,header页眉里的ToolButton { action: newActionId }写法本质上是链接到了menuBar里面的一个action行为。

2.footer页脚里放置了多个TabButton,是为了切换StackView里的页面,采用的是在信号处理器里动态堆栈压入的方式。

3.StackView{initialItem: Rectangle{ color: "grey" }}这给了一个初始项,正常pop是会保留最后一个项的,不会把它出栈掉的。所以打印出来的当前栈深度一直都是2。

四、总结

本节算是对QQuickControls的一个补充总结,介绍了ApplicationWindow和StackView。至此,我认为已经学习到了基本的控件和布局方式。下一节开始将学习一些常用的功能弹窗。

相关推荐
开开心心loky5 小时前
[iOS] KVC 学习
学习·ios·objective-c·cocoa
Kratzdisteln5 小时前
【C语言】Dev-C++如何编译C语言程序?从安装到运行一步到位
c语言·c++
哲Zheᗜe༘6 小时前
了解学习Python编程之python基础
开发语言·python·学习
youliroam6 小时前
成语接龙学习
学习·golang·uniapp·成语接龙
Dream it possible!6 小时前
LeetCode 面试经典 150_栈_有效的括号(52_20_C++_简单)(栈+哈希表)
c++·leetcode·面试··哈希表
kyle~6 小时前
C++--- override 关键字 强制编译器验证当前函数是否重写基类的虚函数
java·前端·c++
寻找华年的锦瑟6 小时前
Qt-配置文件(INI/JSON/XML)
开发语言·qt
HY小海7 小时前
【C++】AVL树实现
开发语言·数据结构·c++
仰泳的熊猫7 小时前
LeetCode:701. 二叉搜索树中的插入操作
数据结构·c++·算法·leetcode