QML 窗口

主窗口是应用程序的基础界面容器,负责承载应用的主要内容和功能。以下是 QML 中实现主窗口的完整方案。

1. 基础主窗口实现

使用 ApplicationWindow (推荐)

qml

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15

ApplicationWindow {
    id: mainWindow
    title: "我的应用"
    width: 1024
    height: 768
    visible: true
    color: "#f5f5f5"
    
    // 菜单栏
    menuBar: MenuBar {
        Menu {
            title: "文件"
            MenuItem { text: "新建"; onTriggered: createNew() }
            MenuItem { text: "打开"; onTriggered: openFile() }
            MenuSeparator {}
            MenuItem { text: "退出"; onTriggered: Qt.quit() }
        }
        Menu {
            title: "帮助"
            MenuItem { text: "关于"; onTriggered: aboutDialog.open() }
        }
    }
    
    // 状态栏
    footer: Label {
        text: "就绪"
        padding: 5
    }
    
    // 主内容区域
    StackView {
        id: contentStack
        anchors.fill: parent
        initialItem: HomePage {}
    }
    
    // 关于对话框
    AboutDialog { id: aboutDialog }
}

2. 主窗口功能扩展

窗口状态管理

qml

ApplicationWindow {
    // ...其他属性...
    
    // 窗口状态持久化
    property var windowSettings: Settings {
        category: "Window"
        property alias x: mainWindow.x
        property alias y: mainWindow.y
        property alias width: mainWindow.width
        property alias height: mainWindow.height
        property alias visibility: mainWindow.visibility
    }
    
    // 最小化到系统托盘
    onVisibilityChanged: {
        if (visibility === Window.Minimized && systemTray.supported) {
            hide()
        }
    }
    
    SystemTrayIcon {
        id: systemTray
        visible: true
        icon.source: "qrc:/icons/app.png"
        onActivated: {
            mainWindow.show()
            mainWindow.raise()
            mainWindow.requestActivate()
        }
    }
}

多文档界面(MDI)实现

qml

ApplicationWindow {
    // ...其他属性...
    
    // MDI区域
    MdiArea {
        id: mdiArea
        anchors.fill: parent
    }
    
    // 新建文档
    function createDocument() {
        var doc = Qt.createQmlObject(`
            import QtQuick 2.15
            MdiWindow {
                title: "文档 ${mdiArea.windows.length + 1}"
                width: 400; height: 300
            }`, mdiArea)
        mdiArea.addWindow(doc)
    }
}

窗口

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    id: mainWindow
    width: 800
    height: 600
    visible: true
    title: "主窗口"
    
    Button {
        text: "打开子窗口"
        onClicked: subWindow.show()
    }
}

3. 主窗口样式定制

自定义标题栏

qml

ApplicationWindow {
    flags: Qt.Window | Qt.FramelessWindowHint
    
    // 自定义标题栏
    Rectangle {
        id: titleBar
        width: parent.width
        height: 40
        color: "#3498db"
        
        DragHandler {
            target: null
            onActiveChanged: if (active) mainWindow.startSystemMove()
        }
        
        Text {
            text: mainWindow.title
            color: "white"
            anchors.left: parent.left
            anchors.leftMargin: 15
            anchors.verticalCenter: parent.verticalCenter
        }
        
        Row {
            anchors.right: parent.right
            anchors.verticalCenter: parent.verticalCenter
            spacing: 5
            
            Button {
                width: 40; height: 40
                text: "━"
                flat: true
                onClicked: mainWindow.visibility = Window.Minimized
            }
            
            Button {
                width: 40; height: 40
                text: "□"
                flat: true
                onClicked: mainWindow.visibility === Window.Maximized ? 
                          mainWindow.showNormal() : mainWindow.showMaximized()
            }
            
            Button {
                width: 40; height: 40
                text: "✕"
                flat: true
                onClicked: mainWindow.close()
            }
        }
    }
    
    // 内容区域
    Item {
        anchors.top: titleBar.bottom
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        // 主内容...
    }
}

4. 主窗口与子窗口通信

使用信号/槽机制

qml

// MainWindow.qml
ApplicationWindow {
    signal openDocumentRequested(string filePath)
    
    function handleDocumentOpened(content) {
        // 处理打开的文件内容
    }
}

// DocumentWindow.qml
Window {
    signal documentSaved(string content)
    
    Button {
        text: "保存到主窗口"
        onClicked: documentSaved("文档内容...")
    }
}

// 在主窗口创建文档窗口时连接信号
function createDocumentWindow() {
    var docWin = Qt.createComponent("DocumentWindow.qml").createObject(mainWindow)
    docWin.documentSaved.connect(mainWindow.handleDocumentOpened)
}

使用单例对象

qml

// AppManager.qml
pragma Singleton
import QtQuick 2.15

QtObject {
    property var mainWindow
    property var currentDocument
    
    function showMessage(text) {
        if (mainWindow) mainWindow.statusBar.showMessage(text)
    }
}

// 在主窗口初始化时注册
ApplicationWindow {
    Component.onCompleted: AppManager.mainWindow = this
}

5. 主窗口最佳实践

  1. 布局结构

    • 使用 ApplicationWindow 作为根元素

    • 合理组织菜单栏、工具栏、状态栏和内容区域

    • 考虑使用 StackView 或 SwipeView 管理多页面

  2. 性能优化

    • 延迟加载不常用的界面部分

    • 使用 Loader 动态加载资源密集型组件

    • 避免在窗口组件中直接包含大量元素

  3. 用户体验

    • 实现窗口状态持久化(位置、大小)

    • 处理多显示器环境

    • 支持高DPI缩放

  4. 跨平台考虑

    • 适配不同操作系统的窗口管理习惯

    • 处理平台特定的菜单和快捷键

    • 考虑移动端和桌面端的差异

7. 完整主窗口示例

qml

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Window 2.15
import Qt.labs.settings 1.0

ApplicationWindow {
    id: appWindow
    title: "文本编辑器"
    minimumWidth: 800
    minimumHeight: 600
    visible: true
    
    // 持久化窗口状态
    Settings {
        category: "Window"
        property alias x: appWindow.x
        property alias y: appWindow.y
        property alias width: appWindow.width
        property alias height: appWindow.height
        property alias visibility: appWindow.visibility
    }
    
    // 菜单栏
    menuBar: AppMenuBar {}
    
    // 工具栏
    header: ToolBar {
        contentHeight: 40
        
        Row {
            spacing: 5
            anchors.verticalCenter: parent.verticalCenter
            
            ToolButton { action: newFileAction }
            ToolButton { action: openFileAction }
            ToolSeparator {}
            ToolButton { action: saveAction }
        }
    }
    
    // 状态栏
    footer: StatusBar {
        Label { id: statusLabel; text: "就绪" }
    }
    
    // 主内容区域
    SplitView {
        anchors.fill: parent
        
        // 导航面板
        NavigationPanel {
            SplitView.preferredWidth: 200
        }
        
        // 编辑区域
        EditorArea {
            id: editor
            SplitView.fillWidth: true
        }
    }
    
    // 动作定义
    Action {
        id: newFileAction
        text: "新建"
        shortcut: StandardKey.New
        onTriggered: editor.newFile()
    }
    
    // 其他动作...
    
    // 初始化
    Component.onCompleted: {
        if (Qt.platform.os === "windows") {
            appWindow.color = "#f0f0f0"
        }
    }
}

8、窗口的静态创建与动态创建

在 QML 中,窗口可以通过静态和动态两种方式创建,各有其适用场景和优缺点。以下是两种方式的详细对比和实现方法。

1). 静态创建窗口

静态创建是指在 QML 文件中直接声明窗口组件。

// MainWindow.qml
import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    id: mainWindow
    width: 800
    height: 600
    visible: true
    title: "主窗口"
    
    Button {
        text: "打开子窗口"
        onClicked: subWindow.show()
    }
}

// 静态创建的子窗口
Window {
    id: subWindow
    width: 400
    height: 300
    title: "静态子窗口"
}

2). 动态创建窗口

动态创建是指在运行时根据需要创建窗口实例。

// MainWindow.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15

Window {
    id: mainWindow
    width: 800
    height: 600
    visible: true
    title: "主窗口"
    
    Button {
        text: "动态创建窗口"
        onClicked: {
            // 方法1:使用createObject
            var component = Qt.createComponent("DynamicWindow.qml")
            if (component.status === Component.Ready) {
                var window = component.createObject(mainWindow, {
                    title: "动态窗口"
                })
                window.show()
            }
            
            // 方法2:使用createWindow (Qt 5.15+)
            // Qt.createQmlObject('import QtQuick.Window 2.15; Window {}', 
            //                  mainWindow, "dynamicWindow")
        }
    }
}

// DynamicWindow.qml
import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    width: 400
    height: 300
    color: "lightblue"
    
    Component.onCompleted: console.log("动态窗口已创建")
    onClosing: destroy() // 关闭时销毁窗口
}