# QMainWindow 教学综合示例(qt_mainwindow_showcase) 覆盖川大 wiki「5 QMainWindow」(pageId 58954529,https://wiki.suncaper.net/display/scu2023/5+QMainWindow) 的 **5.1–5.6 全部六大核心组件**,形态为**极简文本编辑器**(`QTextEdit` 中心部件), 纯组件演示、**无文件 I/O**。主窗体结构用 **Qt Designer(`.ui`)** 设计,应用图标与动作图标 走 **资源文件(`.qrc`)**。 > 仓库已有 `p03/ch05/` 的零散单组件示例(central_widget、dock_widget);本示例是 > **综合演示**,把六者整合到一个 `QMainWindow` 程序里,并能交互操控它们。 ## 六大组件 ↔ 代码映射 | wiki | 组件 | 代码位置 | 演示的 API | |---|---|---|---| | 5.5 | 中心部件 | `mainwindow.ui`:`centralwidget/textEdit`;`.cpp`:`textChanged`/`cursorPositionChanged → updateStatusBar` | `setCentralWidget(QTextEdit)` | | 5.1 | 菜单栏 | `.ui`:`menubar` + `menuFile/menuView/menuHelp/menuToolBarArea` + 12 个 `QAction`;`.cpp`:`on_action*_triggered/toggled` | `menuBar()`/`addMenu`/`QAction` | | 5.2 | 工具栏 | `.ui`:`mainToolBar`(复用 `QAction`);`.cpp`:`setMovable`/`setAllowedAreas`/`setVisible` | `addToolBar`/`setAllowedAreas`/`setMovable` | | 5.3 | 状态栏 | `.cpp`:`addPermanentWidget(statusPosLabel)`/`showMessage` | `addWidget`/`insertWidget`/`removeWidget`(见下) | | 5.4 | 浮动窗口 | `.ui`:`dockWidget`;`.cpp`:`setFloating`/`setAllowedAreas` | `QDockWidget`/`addDockWidget` | | 5.6 | 资源文件 | `mainwindow.qrc` + `.ui` 的 `windowIcon` + 各 `QAction` 图标 | `:/icons/*.png` | ## 关键设计点 ### 1. QAction 是菜单项与工具按钮的公共抽象(5.1) 12 个 `QAction` 在 `.ui` 的 `MainWindow` widget 内**定义一次**,被菜单和工具栏**共同引用** (``)——这正是 wiki 强调的「同一动作,加进菜单显示为菜单项、 加进工具栏显示为工具按钮」。例如 `actionNew` 同时出现在「文件」菜单和主工具栏。 ### 2. 信号槽:on_\_\ 自动连接 槽命名遵循 Qt 约定,由 `setupUi()` 触发的 `QMetaObject::connectSlotsByName` **自动连接**, 无需手写 `connect`(KISS)。例如 `on_actionToggleDockFloating_triggered()` 自动连接 `actionToggleDockFloating` 的 `triggered` 信号。 ### 3. 视图菜单 = 「操控」各组件的入口 | 动作 | 行为 | 对应组件/API | |---|---|---| | 显示主工具栏 ✓ | `mainToolBar->setVisible(checked)` | 5.2 | | 显示状态栏 ✓ | `statusBar()->setVisible(checked)` | 5.3 | | 工具栏可移动 ✓ | `mainToolBar->setMovable(checked)` | 5.2 `setMovable` | | 停靠窗口浮动/停靠 | `dockWidget->setFloating(!isFloating())` | 5.4 `setFloating` | | 显示浮动窗口 | `dockWidget->show()` | 5.4 重新显示(被 X 关闭后找回) | | 关闭浮动窗口 | `dockWidget->hide()` | 5.4 直接隐藏 | | 工具栏停靠区(子菜单 5 项) | `mainToolBar->setAllowedAreas(...)` | 5.2 `setAllowedAreas` | ### 4. 状态栏 API(5.3) 运行时演示 `addPermanentWidget`(永久「行:列 字数」标签)+ `showMessage`(动作临时提示)。 其余三 API 的等价用法(教学参考): ```cpp // addWidget:在状态栏左侧添加普通部件(非永久,会挤占临时消息区) statusBar()->addWidget(new QLabel("就绪")); // insertWidget:在 index 位置插入部件 statusBar()->insertWidget(0, new QLabel("插入")); // removeWidget:移除某部件 statusBar()->removeWidget(someLabel); ``` ## 目录结构 ``` mainwindow_showcase/ ├── mainwindow.ui # Designer 表单:主窗体结构 + 12 个 QAction ├── mainwindow_showcase.h/.cpp # MainWindow 类(动态行为) ├── main.cpp # QApplication + offscreen 自动退出 ├── mainwindow.qrc # 资源清单(5 个图标) ├── gen_icons.py # 图标生成脚本(标准库,无依赖) ├── icons/ # app/new/quit/about/dock.png(gen_icons.py 产物) └── README.md # 本文档 ``` ## 构建与运行(Windows + MinGW 7.3.0 + Qt 5.14.2) > 必须用与 Qt 5.14.2 ABI 匹配的 mingw730_64(`E:/Qt/Qt5.14.2/Tools/mingw730_64`), > 不可用 PATH 中可能存在的更高版本 g++。 ```bash # 1) 生成图标 python docs/teaching/examples/mainwindow_showcase/gen_icons.py # 2) 配置(在仓库根;本示例随 docs/teaching/examples 一起被顶层 CMakeLists 收录) cmake -S . -B build_mw -G "MinGW Makefiles" \ -DCMAKE_PREFIX_PATH=E:/Qt/Qt5.14.2/5.14.2/mingw73_64 \ -DCMAKE_CXX_COMPILER=E:/Qt/Qt5.14.2/Tools/mingw730_64/bin/g++.exe \ -DCMAKE_C_COMPILER=E:/Qt/Qt5.14.2/Tools/mingw730_64/bin/gcc.exe # 3) 构建单目标 cmake --build build_mw --target qt_mainwindow_showcase # 4) 运行(GUI) PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/bin:$PATH \ QT_QPA_PLATFORM_PLUGIN_PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/plugins/platforms \ ./build_mw/docs/teaching/examples/qt_mainwindow_showcase.exe # 5) 离屏自动退出验证(退出码应为 0) QT_QPA_PLATFORM=offscreen \ QT_QPA_PLATFORM_PLUGIN_PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/plugins/platforms \ PATH=/e/Qt/Qt5.14.2/5.14.2/mingw73_64/bin:$PATH \ ./build_mw/docs/teaching/examples/qt_mainwindow_showcase.exe; echo "exit=$?" ``` ## 教学要点小结 - 一个 `QMainWindow` = 菜单栏(≤1)+ 工具栏(多个)+ 状态栏(1)+ 浮动窗口(多个)+ 中心部件(1)。 - `QAction` 是「动作」的抽象,菜单与工具栏共享。 - 工具栏/浮动窗口都是**可移动**的,停靠区域可由 `setAllowedAreas` 限定。 - 资源文件(`.qrc`)把图标编译进可执行文件,运行时用 `:/...` 引用,无需关心磁盘文件。