第 4 章 布局管理
写 GUI 时,不要用绝对坐标摆控件,而是把控件交给布局管理器(layout)。窗口一缩放、字体一换、翻译一切换,布局能自动调整,而绝对坐标会立刻崩盘。
4.1 布局的核心思想
List item
布局管理器负责两件事:
- 分配几何:根据每个子控件的
sizeHint()/sizePolicy()计算出位置和大小。 - 传播尺寸约束:把子控件的最小/最大尺寸聚合起来,反馈给父窗口。
一个控件被addWidget()到某个 layout 后,layout 会接管它的几何,你手动move()/resize()会被立即覆盖。
4.2 常用布局
QHBoxLayout:水平排列。QVBoxLayout:垂直排列。QGridLayout:网格,支持跨行/跨列。QFormLayout:两列「标签 : 控件」的表单,自动按平台风格对齐。QStackedLayout:同一位置堆叠多页,一次显示一页(常配QStackedWidget)。
auto*root=newQVBoxLayout(this);auto*form=newQFormLayout;form->addRow("姓名:",newQLineEdit);form->addRow("年龄:",newQSpinBox);root->addLayout(form);auto*buttons=newQHBoxLayout;buttons->addStretch();// 把后面的按钮推到右边buttons->addWidget(newQPushButton("确定"));buttons->addWidget(newQPushButton("取消"));root->addLayout(buttons);传入new QVBoxLayout(this)会把 layout 直接安装到当前 widget 上,等价于setLayout(new QVBoxLayout)。
4.3 尺寸策略(SizePolicy)
每个 widget 有一对QSizePolicy,告诉布局「愿不愿意拉伸/压缩」:
Fixed:钉死在sizeHint()。Minimum:可以比 hint 大,但不能小(如按钮)。Preferred(默认):hint 是理想值,可大可小。Expanding:主动占据剩余空间(如QTextEdit)。MinimumExpanding、Maximum、Ignored:更专门的场景。
当多个控件都Expanding时,stretch factor决定它们瓜分空间的比例:
layout->addWidget(list,1);// 占 1 份layout->addWidget(editor,3);// 占 3 份4.4 QSplitter
需要让用户拖动分界线调整两块区域时,用QSplitter而不是普通 layout:
auto*splitter=newQSplitter(Qt::Horizontal);splitter->addWidget(fileTree);splitter->addWidget(editor);splitter->setStretchFactor(1,1);// 右侧优先获得多余空间4.5 用 Designer 画布局
.ui文件里推荐的做法:
- 把所有控件先随意扔到窗口上。
- 框选一组控件 → 右键 →Layout→ 选择水平/垂直/网格。
- 最外层布局:选中窗口本身 → 右键 →Layout in Grid/Vertical/Horizontal,顶层没设 layout 的窗口无法自动缩放。
一个常见错误:忘记给顶层窗口加 layout,导致运行时窗口一缩放,控件全挤在左上角。
第 5 章 常用控件
Qt Widgets 控件太多,这里只挑最常用的分组介绍,查 API 用Qt Assistant或官方文档最快。
5.1 按钮与选择
QPushButton:普通按钮,常用信号clicked()。QToolButton:图标按钮,常配QAction。QCheckBox:多选,信号toggled(bool)。QRadioButton:单选,一组内互斥;用QButtonGroup把跨父控件的一组绑起来。QComboBox:下拉列表,currentIndexChanged(int)、currentTextChanged(QString)。
5.2 输入控件
QLineEdit:单行文本。可设setEchoMode(QLineEdit::Password)、setValidator()。QTextEdit/QPlainTextEdit:多行文本。前者支持富文本,后者更适合代码/日志(性能好)。QSpinBox/QDoubleSpinBox:数值输入,自带步进。QDateEdit/QTimeEdit/QDateTimeEdit:日期时间,可弹出日历。QSlider/QDial:滑块与旋钮。
5.3 显示控件
QLabel:文字或图像,支持简单 HTML。QProgressBar:进度条,设setRange(0, 0)变成「忙碌指示」。QLCDNumber:老式七段数码显示。
5.4 容器控件
QGroupBox:带标题的分组框。QTabWidget:标签页。QStackedWidget:堆叠页,setCurrentIndex()切换。QScrollArea:内容超出时提供滚动条。QToolBox:抽屉式分组。
5.5 视图控件(Item Views)
QListWidget/QTreeWidget/QTableWidget:便利类,数据直接塞控件,适合 <1 万条的小数据。QListView/QTreeView/QTableView:Model/View 版本,需要单独提供 model,数据量大或需要多视图共享数据时用它们。详见第 8 章。
5.6 一个组合例子
auto*widget=newQWidget;auto*layout=newQFormLayout(widget);auto*nameEdit=newQLineEdit;auto*ageSpin=newQSpinBox;ageSpin->setRange(0,150);auto*okBtn=newQPushButton("提交");layout->addRow("姓名:",nameEdit);layout->addRow("年龄:",ageSpin);layout->addRow(okBtn);QObject::connect(okBtn,&QPushButton::clicked,widget,[=]{qDebug()<<nameEdit->text()<<ageSpin->value();});widget->show();第 6 章 主窗口:菜单、工具栏、状态栏
QMainWindow是一个预置了菜单栏、工具栏、状态栏、中央区、Dock 区的顶层窗口,大部分桌面应用都以它为骨架。
6.1 结构
┌───────────────── QMenuBar ────────────────┐ ├──────────────── QToolBar(可多个)─────────┤ │ ┌───┐ ┌───┐ │ │ │ D │ CentralWidget │ D │ │ │ │ o │ (setCentralWidget) │ o │ │ │ │ c │ │ c │ │ │ │ k │ │ k │ │ │ └───┘ └───┘ │ ├──────────────── QStatusBar ───────────────┤ └────────────────────────────────────────────┘6.2 QAction:命令的抽象
菜单项、工具栏按钮、快捷键共用同一个QAction,状态(启用/禁用/勾选)自动同步。
auto*openAct=newQAction(QIcon(":/icons/open.svg"),"打开(&O)...",this);openAct->setShortcut(QKeySequence::Open);// Ctrl+O(跨平台)openAct->setStatusTip("打开一个文件");connect(openAct,&QAction::triggered,this,&MainWindow::openFile);menuBar()->addMenu("文件(&F)")->addAction(openAct);addToolBar("主工具栏")->addAction(openAct);字符串中的&O定义了助记符(Alt+O)。QKeySequence::Open等标准键在不同平台会自动映射(如 macOS 变成 ⌘O)。
6.3 状态栏
statusBar()->showMessage("就绪",3000);// 3 秒后自动清除statusBar()->addPermanentWidget(newQLabel("行 1, 列 1"));6.4 Dock 与中央区
auto*dock=newQDockWidget("项目",this);dock->setWidget(projectTree);addDockWidget(Qt::LeftDockWidgetArea,dock);setCentralWidget(editor);