目录
一.多元素控件
1、List Widget
【使用 ListWidget】
2、Table Widget
【使用 QTableWidget】
3、Tree Widget
【使用 QTreeWidget】
二、容器类控件
1、Group Box
【给麦当劳案例加上分组框】
2、Tab Widget
【使用标签页管理多组控件】
三、布局管理器
1、垂直布局
【使用 QVBoxLayout 管理多个控件】
【创建两个 QVBoxLayout】
2、水平布局
【使用 QHBoxLayout 管理控件】
【嵌套的 layout】
3、网格布局
【使用 QGridLayout 管理元素】
【设置 QGridLayout 中元素的大小比例】
【设置垂直方向的拉伸系数】
4、表单布局
【使用 QFormLayout 创建表单】
5、Spacer
【创建一组左右排列的按钮】
一.多元素控件
Qt 中提供的多元素控件有:
- QListWidget
- QListView
- QTableWidget
- QTableView
- QTreeWidget
- QTreeView
xxWidget 和 xxView 之间的区别
以 QTableWidget 和 QTableView 为例。
QTableView 是基于 MVC 设计的控件。
- QTableView 自身不持有数据,使用 QTableView 的时候需要用户创建一个 Model 对象(比如 QStandardModel),并且把 Model 和 QTableView 关联起来。
- 后续修改 Model 中的数据就会影响 QTableView 的显示,修改 QTableView 的显示也会影响到 Model 中的数据(双向绑定)。
QTableWidget 是 QTableView 的子类,对 QTableView 进行了扩展,将 Model 进行了封装,不需要用户手动创建 Model 对象,直接就可以往 QTableWidget 中添加数据了。
1、List Widget
使用 QListWidget 能够显示一个纵向的列表组件。形如:
每个选项都可以被选中。
核心属性:
属性 | 说明 |
currentRow | 当前被选中的是第几行 |
count | 一共有多少行 |
sortingEnabled | 是否允许排序 |
isWrapping | 是否允许换行 |
itemAlignment | 元素的对齐方式 |
selectRectVisible | 被选中的元素矩形是否可见 |
spacing | 元素之间的间隔 |
核心方法
方法 | 说明 |
addItem(const QString& label) | 列表中添加元素 |
currentItem() | 返回 |
setCurrentItem(QListWidgetItem* item) | 设置选中哪个元素 |
setCurrentRow(int row) | 设置选中第几行的元素 |
insertItem(const QString& label, int row) | 在指定的位置插入元素 |
item(int row) | 返回 |
takeItem(int row) | 删除指定行的元素, 返回 |
核心信号
信号 | 说明 |
currentItemChanged(QListWidgetItem* current, QListWidgetItem* old) | 选中不同元素时会触发. 参数是当前选中的元素和之前选中的元素 |
currentRowChanged(int) | 选中不同元素时会触发. 参数是当前选中元素的行数 |
itemClicked(QListWidgetItem* item) | 点击某个元素时触发 |
itemDoubleClicked(QListWidgetItem* item) | 双击某个元素时触发 |
itemEntered(QListWidgetItem* item) | 鼠标进入元素时触发 |
在上述介绍中涉及到⼀个关键的类:Q List Widget Item,这个类表示 QListWidget 中的一个元素。核心方法如下,本质上就是⼀个 “文本+图标” 构成的。
- setFont: 设置字体
- setIcon: 设置图标
- setHidden: 设置隐藏
- setSizeHint: 设置尺寸
- setSelected: 设置是否选中
- setText: 设置文本
- setTextAlignment: 设置文本对齐方式
这些方法允许我们自定义 Q List Widget Item
的外观和行为。
通过结合使用 QListWidget
的属性、方法和信号,以及 QListWidgetItem
的方法,可以创建高度定制化的列表控件。
【使用 ListWidget】
(1)在界面上创建一个 ListView,右键 => 变形为 => ListWidget,再创建一个 lineEdit 和两个按钮
注意:
- ListWidget 是 ListView 的子类,功能比 ListView 更丰富。
- 我们使用 ListWidget 即可。
(2)编写 widget.cpp,在构造函数中添加初始元素
或者直接在图形化界面选择 “编辑项目”:
(3)编写 listWidget 的 slot 函数
此处需要判定 current 和 previous 非空,初始情况下是没有元素选中的,就导致这两个指针可能是 NULL。
这⾥需要给 widget.h 前⾯加上 #include <QListWidgetItem>。
(4)编写按钮的 slot 函数
(5)执行程序
可以新增元素,选中元素,删除元素
2、Table Widget
使用 QTableWidget 表示一个表格控件。一个表格中包含若干行,每一行又包含若干列。
表格中的每个单元格,是一个 QTableWidge tItem 对象。
QTableWidget 核心方法
方法 | 说明 |
item(int row, int column) | 根据行数列数获取指定的 |
setItem(int row, int column, QTableWidgetItem*) | 根据行数列数设置表格中的元素 |
currentItem() | 返回被选中的元素 |
currentRow() | 返回被选中元素是第几行 |
currentColumn() | 返回被选中元素是第几列 |
row(QTableWidgetItem*) | 获取指定 |
column(QTableWidgetItem*) | 获取指定 |
rowCount() | 获取行数 |
columnCount() | 获取列数 |
insertRow(int row) | 在第 |
insertColumn(int column) | 在第 |
removeRow(int row) | 删除第 |
removeColumn(int column) | 删除第 |
setHorizontalHeaderItem(int column, QTableWidgetItem*) | 设置指定列的表头 |
setVerticalHeaderItem(int row, QTableWidgetItem*) | 设置指定行的表头 |
QTableWidge tItem 核心信号
信号 | 说明 |
cellClicked(int row, int column) | 点击单元格时触发 |
cellDoubleClicked(int row, int column) | 双击单元格时触发 |
cellEntered(int row, int column) | 鼠标进入单元格时触发 |
currentCellChanged(int row, int column, int previousRow, int previousColumn) | 选中不同单元格时触发 |
QTableWidge tItem 核心方法
方法 | 说明 |
row() | 获取当前是第几行 |
column() | 获取当前是第几列 |
setText(const QString&) | 设置文本 |
setTextAlignment(int) | 设置文本对齐 |
setIcon(const QIcon&) | 设置图标 |
setSelected(bool) | 设置被选中 |
setSizeHint(const QSize&) | 设置尺寸 |
setFont(const QFont&) | 设置字体 |
可以通过这些 属性和方法来动态地添加、移除或修改表格内容,以及定制单元格的表现形式,包括文本、对齐方式、图标等。
同时,利用信号可以实现用户交互逻辑,如当用户点击或双击单元格时执行特定的操作。
【使用 QTableWidget】
(1)在界面上创建 QTableWidget 和 三个按钮,一个输入框
注意:QTableWidget 是 QTableView 的子类,功能比 QTableView 更丰富。我们使用 QTableWidget 即可。
(2)编写 widget.cpp 构造函数,构造表格中的初始数据
(3)编写按钮的 slot 函数
(4)执行程序,即可完成表格的基本操作
默认情况下,单元格中的内容直接就是可编辑的。
如果不想让用户编辑,可以设置
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
3、Tree Widget
- 使用 QTreeWidget (树整体 的管理) 表示一个树形控件,里面的每个元素都是一个 QTreeWidge tItem(选中的 某个节点 管理),每个 QTreeWidgetItem 可以包含多个文本和图标,每个文本 / 图标为一个列。
- 可以给 QTreeWidget 设置顶层节点(顶层节点可以有多个),然后再给顶层节点添加子节点,从而构成树形结构。
QTreeWidget 核心方法
方法 | 说明 |
clear() | 清空所有子节点 |
addTopLevelItem(QTreeWidgetItem* item) | 新增顶层节点 |
topLevelItem(int index) | 获取指定下标的顶层节点 |
topLevelItemCount() | 获取顶层节点个数 |
indexOfTopLevelItem(QTreeWidgetItem* item) | 查询指定节点是顶层节点中的下标 |
takeTopLevelItem(int index) | 删除指定的顶层节点,返回 |
currentItem() | 获取当前选中的节点,返回 |
setCurrentItem(QTreeWidgetItem* item) | 选中指定节点 |
setExpanded(bool) | 展开/关闭节点 |
setHeaderLabel(const QString& text) | 设置 |
QTreeWidget 核心信号
信号 | 说明 |
currentItemChanged(QTreeWidgetItem* current, QTreeWidgetItem* old) | 切换选中元素时触发 |
itemClicked(QTreeWidgetItem* item, int col) | 点击元素时触发 |
itemDoubleClicked(QTreeWidgetItem* item, int col) | 双击元素时触发 |
itemEntered(QTreeWidgetItem* item, int col) | 鼠标进入时触发 |
itemExpanded(QTreeWidgetItem* item) | 元素被展开时触发 |
itemCollapsed(QTreeWidgetItem* item) | 元素被折叠时触发 |
QTreeWidgetItem 核心属性
属性 | 说明 |
text | 持有的文本 |
textAlignment | 文本对齐方式 |
icon | 持有的图标 |
font | 文本字体 |
hidden | 是否隐藏 |
disabled | 是否禁用 |
expanded | 是否展开 |
sizeHint | 尺寸大小 |
selected | 是否选中 |
QTreeWidgetItem 核心方法
方法 | 说明 |
addChild(QTreeWidgetItem* child) | 新增子节点 |
childCount() | 子节点的个数 |
child(int index) | 获取指定下标的子节点,返回 |
takeChild(int index) | 删除对应下标的子节点 |
removeChild(QTreeWidgetItem* child) | 删除对应的子节点 |
parent() | 获取该元素的父节点 |
通过上述提供的方法和信号,可以创建、管理和操作树形结构的数据,并响应用户的交互。QTreeWidgetItem
提供了更多的细粒度控制,允许 定制每个项的表现形式和行为。
【使用 QTreeWidget】
(1)在界面上创建一个 TreeView,右键 => 变形为 => TreeWidget,再创建一个 lineEdit 和两个按钮
注意:TreeWidget 是 TreeView 的子类,功能比 TreeView 更丰富。我们使用 TreeWidget 即可。
(2)编写代码,构造初始数据
(3)编写代码,实现按钮的 slot 函数
(4)执行程序,可以针对树形框进行编辑
💡 count 的设置 ,方便了新增的插入位置的确定
二、容器类控件
1、Group Box
使用 QGroupBox 实现一个带有标题的分组框,可以把其他的控件放到里面作为一组,这样看起来能更好看一点。
注意:不要把 QGroupBox 和 QButtonGroup 混淆(之前在介绍 QRadionButton 的时候提到了 QButtonGroup)。
[Qt] 万字详解 | 常用控件 | Button | Label | LCD | ProgressBar
核心属性:
属性 | 说明 |
title | 分组框的标题 |
alignment | 分组框内部内容的对齐方式 |
flat | 是否是 "扁平" 模式;设置为 |
checkable | 是否可选择;设为 |
checked | 描述分组框的选择状态(前提是 |
分组框 只是一个用来 “美化界面” 这样的组件,并不涉及到用户交互和业务逻辑,属于 “锦上添花"。
【给麦当劳案例加上分组框】
(1)在界面上创建三个分组框,并且在分组框内部创建下拉框和微调框
注意:在复制粘贴控件的时候,一定要先选中对应的父控件,再粘贴。
2、Tab Widget
使用 QTabWidget 实现一个带有标签页的控件,可以往里面添加一些 widget,进一步的就可以通过标签页切换。
核心属性:
属性 | 说明 |
tabPosition | 标签页所在的位置:<br>- North 上方<br>- South 下方<br>- West 左侧<br>- East 右侧 |
currentIndex | 当前选中了第几个标签页(从0开始计算) |
currentTabText | 当前选中的标签页的文本 |
currentTabName | 当前选中的标签页的名字 |
currentTabIcon | 当前选中的标签页的图标 |
currentTabToolTip | 当前选中的标签页的提示信息 |
tabsClosable | 标签页是否可以关闭 |
movable | 标签页是否可以移动 |
核心信号
信号 | 说明 |
currentChanged(int) | 在标签页发生切换时触发,参数为被点击的选项卡编号。 |
tabBarClicked(int) | 在点击选项卡的标签条的时候触发,参数为被点击的选项卡编号。 |
tabBarDoubleClicked(int) | 在双击选项卡的标签条的时候触发,参数为被点击的选项卡编号。 |
tabCloseRequested(int) | 在标签页关闭请求时触发,参数为被请求关闭的选项卡编号。 |
【使用标签页管理多组控件】
(1)在界面上创建一个 QTabWidget 和两个按钮
注意 :
- QTabWidget 中的每个标签页都是⼀个 QWidget
- 点击标签页就可以直接切换
- 右键 QTabWidget,可以添加标签页或者删除标签页
(2)编写 widget.cpp,进行初始化,给标签页中放个简单的 label
注意新创建的 label 的父元素,是 ui->tab 和 ui->tab_2。
Qt 中使用父子关系决定该控件 “在哪里”。
(3)编写按钮的 slot 函数
- 使用 count() 获取到标签页的个数
- 使用 addTab 新增标签页
- 使用 removeTab 删除标签页
- 使用 currentIndex 获取到当前标签页的下标
- 使用 setCurrentIndex 切换当前标签页
(4)编写 QTabWidget 的 currentChanged 函数
(5)运行程序
- 点击新建标签页,可以创建出新的标签
- 点击删除当前标签页,可以删除标签
- 切换标签页时,可以看到 qDebug 打印出的标签页编号
💡 QT Creator格式化代码的快捷键:
Ctrl+I
三、布局管理器
- 之前使用 Qt 在界面上创建的控件都是通过 “绝对定位” 的方式来设定的,也就是每个控件所在的位置都需要计算坐标,最终通过 setGeometry 或者 move 方式摆放过去。
- 这种设定方式其实并不方便,尤其是界面如果 内容比较多,不好计算,而且一个窗口大小往往是可以调整的,按照绝对定位的方式,也无法自适应窗口大小。
- 因此 Qt 引入 “布局管理器”(Layout)机制来解决上述问题。
🎢当然,布局管理器并非 Qt 独有。其他的 GUI 开发框架,像 Android、前端等也有类似的机制。
1、垂直布局
使用 QVBoxLayout 表示垂直的布局管理器,V 是 vertical 的缩写。
核心属性
属性 | 说明 |
layoutLeftMargin | 左侧边距,设置或获取布局内容与容器左边界的距离 |
layoutRightMargin | 右侧边距,设置或获取布局内容与容器右边界的距离 |
layoutTopMargin | 上方边距,设置或获取布局内容与容器上边界的距离 |
layoutBottomMargin | 下方边距,设置或获取布局内容与容器下边界的距离 |
layoutSpacing | 相邻元素之间的间距,设置或获取布局中各元素之间的默认间隔 |
Layout 只是用于界面布局,并没有提供信号。
【⭕使用 QVBoxLayout 管理多个控件】
(1)编写代码,创建布局管理器和三个按钮,并且把按钮添加到布局管理器中
- 使用 addWidget 把控件添加到布局管理器中
- 使用 setLayout 设置该布局管理器到 widget 中
(2)运行程序
可以看到此时界面上的按钮就存在于布局管理器中,随着窗口尺存变化而发生改变。
此时的三个按钮的尺存和位置都是自动计算出来的。
通过上述代码的方式,只能给这个 widget 设定一个布局管理器。
实际上也可以通过 Qt Design 在一个窗口中创建多个布局管理器。
【创建两个 QVBoxLayout】
(1)在界面上创建两个 QVBoxLayout,每个 QVBoxLayout 各放三个按钮
(2)运行程序
可以看到这些按钮已经自动排列好
只不过当前这些按钮的位置不能随着窗口大小自动变化。
通过 Qt Designer 创建的布局管理,其实是先创建了一个 widget,设置过 geometry 属性的,再把这个 layout 设置到这个 widget 中。
实际上,一个 widget 只能包含一个 layout。
打开 ui 文件的原始 xml,可以看到其中的端倪。这种情况下 layout 并非是窗口 widget 的布局管理器,因此不会随着窗口大小改变。
2、水平布局
使用 QHBoxLayout 表示垂直的布局管理器,H 是 horizontal 的缩写。
核心属性(和 QVBoxLayout 属性是一致的)
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutSpacing | 相邻元素之间的间距 |
【使用 QHBoxLayout 管理控件】
(1)编写代码,创建布局管理器和三个按钮,并且把按钮添加到布局管理器中
(2)运行程序
可以看到此时界面上的按钮就存在于布局管理器中,随着窗口尺寸变化而发生改变。
此时的三个按钮的尺存和位置都是自动计算出来的。
Layout 里面可以再嵌套上其他的 layout,从而达到更复杂的布局效果。
【嵌套的 layout】
(1)在代码中创建以下内容
使用 addLayout 给 layout 中添加子 layout:
(2)执行程序
结合 QHBoxLayout 和 QVBoxLayout, 就可以做出各种复杂的界面了。
3、网格布局
Qt 中还提供了 QGridLayout 用来实现网格布局的效果
可以达到 M * N 的这种网格的效果。
核心属性:
属性 | 说明 |
layoutLeftMargin | 左侧边距 |
layoutRightMargin | 右侧边距 |
layoutTopMargin | 上方边距 |
layoutBottomMargin | 下方边距 |
layoutHorizontalSpacing | 相邻元素之间水平方向的间距 |
layoutVerticalSpacing | 相邻元素之间垂直方向的间距 |
layoutRowStretch | 行方向的拉伸系数 |
layoutColumnStretch | 列方向的拉伸系数 |
整体和 QVBoxLayout 以及 QHBoxLayout 相似
但是设置 spacing 的时候是按照垂直水平两个方向来设置的。
【使用 QGridLayout 管理元素】
(1)代码中创建 QGridLayout 和 4 个按钮
使用 addWidget 添加控件到布局管理器中,但是添加的同时会指定两个坐标,表示放在第几行,第几列。
(2)执行代码
可以看到当前的这几个按钮是按照 2 行 2 列的方式排列的
(3)如果调整行列坐标为下列代码
执行代码可以看到这几个按钮都在同一行了,相当于 QHBoxLayout:
(4)如果调整行列坐标为下列代码
执行代码可以看到这几个按钮都在同一列了,相当于 QVBoxLayout:
(5)任意调整行列,即可看到不同的效果
运行
(6)编写代码形如
注意 :
- 设置行和列的时候,如果设置的是一个很大的值,但是这个值和上一个值之间并没有其他的元素,那么并不会在中间腾出额外的空间。
- 虽然把 button4 设置在第 100 行,但是由于 3-99 行没有元素,因此 button4 仍然会紧挨在 button3 下方看起来和上面的 0 1 2 3 的情况是相同的。
【设置 QGridLayout 中元素的大小比例】
(1)创建 6 个按钮,按照 2 行 3 列的方式排列
使用 setColumnStretch 设置每一列的拉伸系数:
(2)执行程序
可以看到每一列的宽度是不同的,并且随着窗口调整动态变化:
- 另外,QGridLayout 也提供了 setRowStretch 设置行之间的拉伸系数。
- 上述案例中,直接设置 setRowStretch 效果不明显,因为每个按钮的高度是固定的。
- 需要把按钮的垂直方向的 sizePolicy 属性设置为 QSizePolicy::Expanding 尽可能填充满布局管理器,才能看到效果。
如果拉伸系数设为 0,意思是不参与拉伸,此时按钮的宽度是固定值。
【设置垂直方向的拉伸系数】
(1)编写代码, 创建 6 个按钮, 按照 3 行 2 列方式排列.
使用 setSizePolicy 设置按钮的尺寸策略,可选的值如下:
- QSizePolicy::Ignored:忽略控件的尺寸,不对布局产生影响。
- QSizePolicy::Minimum:控件的最小尺寸为固定值,布局时不会超过该值。
- QSizePolicy::Maximum:控件的最大尺寸为固定值,布局时不会小于该值。
- QSizePolicy::Preferred:控件的理想尺寸为固定值,布局时会尽量接近该值。
- QSizePolicy::Expanding:控件的尺寸可以根据空间调整,尽可能占据更多空间。
- QSizePolicy::Shrinking:控件的尺寸可以根据空间调整,尽可能缩小以适应空间。
(2)执行代码
此时的按钮垂直方向都舒展开了
并且调整窗口尺寸,也会按照设定的比例同步变化。
总的来说,使用 QGridLayout 能够代替很多 QHBoxLayout 和 QVBoxLayout 嵌套的场景。毕竟嵌套的代码写起来是比较麻烦的。
另外不要忘了,QGridLayout 里面也能嵌套 QHBoxLayout 和 QVBoxLayout,QHBoxLayout 和 QVBoxLayout 里面也能嵌套 QGridLayout。
灵活使用上述布局管理器就可以实现出任意的复杂界面。
4、表单布局
除了上述的布局管理器之外,Qt 还提供了 QFormLayout,属于是 QGridLayout 的特殊情况,专门用于实现两列表单的布局。
这种表单布局多用于让用户填写信息的场景,左侧列为提示,右侧列为输入框。
【使用 QFormLayout 创建表单】
(1)编写代码,创建 QFormLayout,以及三个 label 和三个 lineEdit
- 使用 addRow 方法来添加一行,每行包含两个控件。
- 第一个控件固定是 QLabel / 文本,第二个控件则可以是任意控件。
- 如果把第⼀个参数填写为 NULL,则什么都不显示。
(2)执行程序
5、Spacer
使用布局管理器的时候,可能需要在控件之间添加一段空白,就可以使用 QSpacerItem 来表示。
核心属性:
属性 | 说明 |
width | 宽度 |
height | 高度 |
hData | 水平方向的
|
vData | 垂直方向的 选项同上。 |
上述属性在构造函数设置即可。
【创建一组左右排列的按钮】
(1)在界面上创建一个 QVBoxLayout ,并添加两个按钮
(2)直接运行程序,可以看到两个按钮是紧挨着的
(3)在两个按钮中间添加一个 spacer
(4)运行程序
可以看到两个按钮之间已经存在了间隔了,调整 QSpacerItem 不同的尺寸,即可看到不同的间距:
在 Qt Designer 中,也可以直接给界面上添加 spacer:
Qt 常用控件基本上就讲完啦,完结撒花~
之后应该会写一个小结,然后就继续讲解窗口部分*(੭*ˊᵕˋ)੭*