Qt 控件与布局
Qt 控件与布局核心知识点
本文档旨在帮助你从入门到精通 Qt 的两大基础核心:控件(Widgets)和布局管理器(Layouts)。掌握它们是构建任何复杂、美观且响应式桌面应用程序的基石。
第一部分:常用控件 (QWidget 派生类) 的高级用法与自定义
仅仅会使用控件的 API 是不够的,真正的熟练在于掌握其高级特性并能随心所欲地进行自定义。
1. 核心概念:信号与槽 (Signals & Slots)
这是 Qt 的核心机制,所有控件的交互都基于此。
高级用法:
Lambda 表达式连接: 对于简单的逻辑,可以直接使用 C++11 的 Lambda 表达式,避免创建新的槽函数。
connect(button, &QPushButton::clicked, [=](){label->setText("Button Clicked!"); });
跨线程连接:
connect
函数的第五个参数Qt::ConnectionType
可以指定连接类型,如Qt::QueuedConnection
用于多线程通信。断开连接: 使用
disconnect
函数可以动态地断开信号和槽的连接。
2. 常用控件精讲
a. QLabel
富文本显示:
label->setText("<b>Hello</b> <font color='red'>World!</font>");
可以直接解析 HTML 标签。图片显示: 使用
QPixmap
加载图片并设置给QLabel
。label->setPixmap(QPixmap(":/images/logo.png"));
交互性: 设置
label->setTextInteractionFlags(Qt::TextSelectableByMouse);
使文本可选。通过事件过滤器可以使其响应点击。
b. QPushButton
快捷键:
button->setShortcut(QKeySequence("Ctrl+O"));
自定义外观 (QSS): Qt Style Sheets 是类似 CSS 的机制,可以极大地美化界面。
QPushButton {background-color: #4CAF50; /* 绿色 */border: none;color: white;padding: 10px 20px;text-align: center;border-radius: 8px; } QPushButton:hover {background-color: #45a049; } QPushButton:pressed {background-color: #3e8e41; }
带图标的按钮:
button->setIcon(QIcon(":/icons/save.ico"));
c. QLineEdit
输入掩码 (Input Mask): 限制用户输入格式,如IP地址、电话号码等。
lineEdit->setInputMask("000.000.000.000;_");
校验器 (Validator): 使用
QIntValidator
或QDoubleValidator
限制只能输入整数或浮点数,或通过QRegularExpressionValidator
使用正则表达式进行复杂校验。占位符文本:
lineEdit->setPlaceholderText("请输入用户名...");
添加动作 (Action): 在输入框内添加一个清除或搜索的小图标。
d. QComboBox
自定义模型 (Model): 当数据量很大或来源复杂时,不要直接使用
addItem
,而是继承QAbstractListModel
或QStandardItemModel
,通过setModel()
方法与QComboBox
关联,实现 MVC 模式。自定义视图 (View):
setView(new QListView());
可以改变下拉列表的显示方式。可编辑与自动补全:
setEditable(true)
和setCompleter()
。
e. QListWidget
/ QTableWidget
/ QTreeWidget
(Item-Based Widgets)
这些控件方便易用,但当数据量超过几百条时,性能会下降。
高级用法:
自定义项 (WidgetItem):
QTableWidgetItem
可以设置图标、复选框、背景色等。自定义单元格控件: 使用
setCellWidget()
可以在表格的单元格里放入任何其他控件,如QProgressBar
、QComboBox
等。
何时转向 Model/View 架构: 当你需要处理大量数据、需要自定义显示逻辑、或者数据源是数据库时,就应该放弃这些便利类,转向使用
QListView
/QTableView
/QTreeView
搭配自定义的 Model。
3. 控件自定义的终极武器:继承与重绘
继承
QWidget
: 当 Qt 现有控件无法满足你的需求时,可以直接继承QWidget
,然后重写事件处理函数。paintEvent(QPaintEvent *event)
: 核心中的核心。使用QPainter
在这个函数里绘制任何你想要的界面。mousePressEvent()
,mouseMoveEvent()
,mouseReleaseEvent()
: 处理鼠标交互。keyPressEvent()
: 处理键盘交互。
提升 (Promoting): 在 Qt Designer 中,你可以放置一个标准的
QWidget
,然后右键点击它,选择 "Promote to...",将其提升为你自己编写的自定义控件类。
第二部分:精通布局管理器 (QLayout)
布局管理器是实现自适应 UI 的关键。永远不要手动设置控件的坐标和大小,除非你在制作一个固定大小的启动画面。
1. 基础布局管理器
QHBoxLayout
: 水平布局,将控件从左到右排列。QVBoxLayout
: 垂直布局,将控件从上到下排列。QGridLayout
: 网格布局,将控件放置在指定的行和列。适用于表单、棋盘等界面。addWidget(widget, row, col, rowSpan, colSpan)
:rowSpan
和colSpan
参数可以让一个控件占据多行多列。
QFormLayout
: 表单布局,专门用于标签和输入框的成对排列,自动对齐。
2. 实现复杂布局:嵌套与伸缩因子
嵌套 (Nesting Layouts): 一个布局本身可以被看作一个
QLayoutItem
,因此可以被添加到另一个布局中。通过组合和嵌套,可以实现任何复杂的界面。实践思想: 先从宏观上划分界面区域(如上、下、左、中、右),为每个区域选择合适的布局管理器,然后再对每个区域进行内部的细分。
伸缩因子 (Stretch Factor):
layout->addStretch(int stretch)
: 添加一个可伸缩的空白空间。layout->addWidget(widget, int stretch)
: 第二个参数stretch
指定了该控件在布局方向上应该如何分配多余的空间。比例分配: 如果一个
QHBoxLayout
中有两个QPushButton
,stretch
分别为 1 和 2,那么当窗口拉宽时,多出来的宽度会按照 1:2 的比例分配给这两个按钮。如果stretch
为 0(默认值),则控件不拉伸。
3. QSpacerItem
和 addStretch
的区别
addStretch()
是最常用的,它添加一个QSizePolicy::Expanding
的空白项。QSpacerItem(width, height, horizontalPolicy, verticalPolicy)
提供了更精细的控制,你可以指定水平和垂直方向上的QSizePolicy
,例如创建一个固定大小的空白。
第三部分:理解 sizePolicy
和 sizeHint
这是布局系统工作的核心,决定了控件在布局中的“行为举止”。
1. sizeHint()
- “我想要多大?”
这是一个虚函数,每个控件都会实现它。
它返回一个
QSize
,代表这个控件的理想尺寸或自然尺寸。例如,一个
QPushButton
的sizeHint
取决于它的文本长度和图标大小。一个QLineEdit
的sizeHint
可能有一个合理的默认宽度和基于字体高度的高度。布局管理器会首先查询所有控件的
sizeHint
,作为布局计算的初始依据。
2. sizePolicy()
- “我如何适应变化?”
sizePolicy
告诉布局管理器当有额外空间或空间不足时,控件应该如何被拉伸或压缩。它是一个
QSizePolicy
对象,包含水平策略和垂直策略。常用策略:
QSizePolicy::Fixed
: 控件尺寸就是sizeHint
的尺寸,不能拉伸也不能压缩。QSizePolicy::Minimum
: 控件尺寸不能小于sizeHint
,但可以拉伸。QSizePolicy::Maximum
: 控件尺寸不能大于sizeHint
,但可以压缩。QSizePolicy::Preferred
: 控件尺寸是sizeHint
,但可以被拉伸或压缩。(大部分控件的默认值)QSizePolicy::Expanding
: 控件可以被拉伸或压缩,并且它“渴望”获得尽可能多的空间。(关键策略)QSizePolicy::MinimumExpanding
: 与Expanding
类似,但sizeHint
被视作最小尺寸。不常用。
3. sizePolicy
与 stretch
的协同工作
sizePolicy
决定一个控件是否愿意伸缩。stretch
决定当多个控件都愿意伸缩时,多余的空间如何分配。
一个典型的例子: 想象一个对话框,底部有两个按钮:“确定”和“取消”。我们希望它们靠右显示。
创建一个
QHBoxLayout
。layout->addStretch(1);
// 在左边添加一个“贪婪”的空白,它会占据所有多余的空间。layout->addWidget(okButton);
layout->addWidget(cancelButton);
在这个例子中,okButton
和 cancelButton
的 sizePolicy
通常是 Preferred
或 Minimum
,它们不会主动拉伸。而 addStretch()
添加的空白项的 sizePolicy
是 Expanding
,伸缩因子为 1。因此,当窗口变宽时,所有多余的空间都被这个空白项“吃掉”,从而把按钮推到了最右边。
总结: 要构建一个灵活、自适应的 UI,你需要:
选择并嵌套正确的布局管理器来划分界面结构。
为需要按比例分配空间的控件设置伸缩因子 (stretch)。
为特殊行为的控件调整其
sizePolicy
(例如,一个水平分隔线的高度应该是Fixed
,但宽度应该是Expanding
)。如果你在自定义控件,请务必提供一个合理的
sizeHint
。