# 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 内**定义一次**，被菜单和工具栏**共同引用**
（`<addaction name="..."/>`）——这正是 wiki 强调的「同一动作，加进菜单显示为菜单项、
加进工具栏显示为工具按钮」。例如 `actionNew` 同时出现在「文件」菜单和主工具栏。

### 2. 信号槽：on_\<objectName\>_\<signal\> 自动连接
槽命名遵循 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`）把图标编译进可执行文件，运行时用 `:/...` 引用，无需关心磁盘文件。
