
输入类控件我们基本了解之后,我们接下来来学习多元素控件!
多元素控件
Qt 中提供的多元素控件有:
列表
-
QListWidget
-
QListView
表格
-
QTableWidget
-
QTableView
树形:比如目录
-
QTreeWidget
-
QTreeView
💡 xxWidget 和 xxView 之间的区别 以 QTableWidget 和 QTableView 为例。
QTableView 是基于 MVC(MVC --- model:数据,view:视图,controller:控制器 --- 也是软件开发中,非常经典的软件结构的组织形式了) 设计的控件. QTableView 自身不持有数据. 使用 QTableView 的时候需要用户创建一个 Model 对象 (比如 qStandardItem ), 并且把 Model 和 QTableView 关联起来. 后续修改 Model 中的数据就会影响 QTableView 的显示; 修改 QTableView 的显示也会影响到 Model 中的数据(双向绑定).
QTableWidget 则是 QTableView 的子类, 对 Model 进行了封装. 不需要用户手动创建 Model 对象, 直接就可以在 QTableWidget 中添加数据了.
xxView 是更底层的实现,xxWidget 是基于 xxView 封装而来的!
List Widget
使用 QListWidget 能够显示一个纵向的列表. 形如:
每个选项都可以被选中.
核心属性
属性 | 说明 |
---|---|
currentRow | 当前被选中的是第几行 |
count | 一共有多少行 |
sortingEnabled | 是否允许排序 |
isWrapping | 是否允许换行 |
itemAlignment | 元素的对齐方式 |
selectRectVisible | 被选中的元素矩形是否可见 |
spacing | 元素之间的间隔 |
核心方法
方法 | 说明 |
---|---|
addItem(const QString& label) addItem(QListWidgetItem *item) | 列表中添加元素 |
addItem(const QString& label) addItem(QListWidgetItem *item) | |
currentItem() | 返回 QListWidgetItem* 表示当前选中的元素 |
setCurrentItem(QListWidgetItem* item) | 设置选中哪个元素 |
setCurrentRow(int row) | 设置选中第几行的元素 |
insertItem(const QString& label, int row) insertItem(QListWidgetItem *item, int row) | 在指定的位置插入元素 |
insertItem(const QString& label, int row) insertItem(QListWidgetItem *item, int row) | 此处的row参数就表示插入完毕之后,新的元素在第几行,把新元素插在第几行之前(你超过了第二名之后,你是第几?是第二啦) |
item(int row) | 返回 QListWidgetItem* 表示第 row 行的元素 |
takeItem(int row) | 删除指定行的元素,返回 QListWidgetItem* 表示是哪个元素被删除了 |
核心信号
方法 | 说明 |
---|---|
currentItemChanged(QListWidgetItem* current, QListWidgetItem* old) | 选中不同元素时会触发. 参数是当前选中的元素和之前选中的元素. |
currentRowChanged(int) | 选中不同元素时会触发. 参数是当前选中元素的行数. |
itemClicked(QListWidgetItem* item) | 点击某个元素时触发 |
itemDoubleClicked(QListWidgetItem* item) | 双击某个元素时触发 |
itemEntered(QListWidgetItem* item) | 鼠标进入元素时触发 |
在上述介绍中,涉及到一个关键的类,QListWidgetItem
这个类表示 QListWidget 中的一个元素!
核心方法如下:本质上就是一个"文本+图标"构成的:
QListWidgetItem 的核心方法
方法 | 说明 |
---|---|
setFont | 设置字体 |
setIcon | 设置图标 |
setHidden | 设置隐藏 |
setSizeHint | 设置尺寸 |
setSelected | 设置是否选中 |
setText | 设置文本 |
setTextAlignment | 设置文本对齐方式 |
代码示例: 使用 ListWidget
1.在界面上创建一个 ListView, 右键 -> 变形为 -> ListWidget, 再创建一个 lineEdit 和两个按钮.
注意: ListWidget 是 ListView 的子类, 功能比 ListView 更丰富, 咱们使用 ListWidget 即可.

2.编写 widget.cpp, 在构造函数中添加初始元素
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 往这里添加一些元素
ui->listWidget->addItem("C++");
ui->listWidget->addItem("Java");
ui->listWidget->addItem("Python");
// 在 QListWidgetItem 中,可以设置字体属性,设置属性,设置文字大小,设置是否被选中等状态!
// ui->listWidget->addItem(new QListWidgetItem("C++"));
// ui->listWidget->addItem(new QListWidgetItem("Java"));
// ui->listWidget->addItem(new QListWidgetItem("Python"));
}
我们也可以在图形化界面中,右击 QListWidget 选择编辑项目,就可以直接添加内容了,如果这里的初始化内容是固定的,此时我们通过哪种方式都可以,但是这里的内容不是固定的,要通过读取文件/网络来构造数据!就需要通过代码的方式来添加了!
3.编写 listWidget 的 slot 函数
此处需要判定 current 和 previous 非空. 初始情况下是没有元素选中的, 就导致这俩指针可能是 NULL
cpp
void Widget::on_listWidget_currentItemChanged(QListWidgetItem * current, QListWidgetItem * previous)
{
if (current != NULL && previous != NULL) {
qDebug() << "当前选中: " << current->text()
<< "之前选中: " << previous->text();
}
}
这里需要给 widget.h 前面加上 #include <QListWidgetItem>
4.编写按钮的 slot 函数
cpp
void Widget::on_pushButton_clicked()
{
// 1.先获取到输入框中的内容。
const QString& text = ui->lineEdit->text();
// 2.添加到 QListWidget 中
if(text == "")
{
return;
}
ui->listWidget->addItem(text);
}
void Widget::on_pushButton_2_clicked()
{
// 1.获取到被选中的元素是哪一个
int row = ui->listWidget->currentRow();
if(row < 0)
{
return;
}
// 2.按照行号来删除元素
ui->listWidget->takeItem(row);
}
5.执行程序, 观察效果. 可以新增元素, 选中元素, 删除元素.

Table Widget
使用 QTableWidget 表示一个表格控件. 一个表格中包含若干行, 每一行又包含若干列. 表格中的每个单元格, 是一个 QTableWidgetItem 对象.
QTableWidget 核心方法
方法 | 说明 |
---|---|
item(int row, int column) | 根据行数列数获取指定的 QTableWidgetItem* |
setItem(int row, int column, QTableWidgetItem*) | 根据行数列数设置表格中的元素 |
currentItem() | 返回被选中的元素 QTableWidgetItem* |
currentRow() | 返回被选中元素是第几行 |
currentColumn() | 返回被选中元素是第几列 |
row(QTableWidgetItem*) | 获取指定 item 是第几行 |
column(QTableWidgetItem*) | 获取指定 item 是第几列 |
rowCount() | 获取行数 |
columnCount() | 获取列数 |
insertRow(int row) | 在第 row 行处插入新行 |
insertColumn(int column) | 在第 column 列插入新列 |
removeRow(int row) | 删除第 row 行 |
removeColumn(int column) | 删除第 column 列 |
setHorizontalHeaderItem(int column, QTableWidgetItem*) | 设置指定列的表头(描述内容信息) |
setVerticalHeaderItem(int row, QTableWidgetItem*) | 设置指定行的表头 |
QTableWidgetItem 核心信号
信号 | 说明 |
---|---|
cellClicked(int row, int column) | 点击单元格时触发 |
cellDoubleClicked(int row, int column) | 双击单元格时触发 |
cellEntered(int row, int column) | 鼠标进入单元格时触发 |
currentCellChanged(int row, int column, int previousRow, int previousColumn) | 选中不同单元格时触发 |
QTableWidgetItem 核心方法
方法 | 说明 |
---|---|
row() | 获取当前是第几行 |
column() | 获取当前是第几列 |
setText(const QString&) | 设置文本 |
setTextAlignment(int) | 设置文本对齐 |
setIcon(const QIcon&) | 设置图标 |
setSelected(bool) | 设置被选中 |
setSizeHints(const QSize&) | 设置尺寸 |
setFont(const QFont&) | 设置字体 |
代码示例: 使用 QTableWidget
1.在界面上创建 QTableWidget 和 三个按钮, 一个输入框

注意: QTableWidget 是 QTableView 的子类, 功能比 QTableView 更丰富. 咱们使用 QTableWidget 即可.
2.编写 widget.cpp 构造函数, 构造表格中的初始数据.
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 对表格中的数据进行初始化 --- 我们可以使用代码,也可以使用图形化界面的方式
// 创建三行
ui->tableWidget->insertRow(0);
ui->tableWidget->insertRow(1);
ui->tableWidget->insertRow(2);
// 创建三列
ui->tableWidget->insertColumn(0);
ui->tableWidget->insertColumn(1);
ui->tableWidget->insertColumn(2);
// 给三个列设置列名,也就是设置水平方向的表头
ui->tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("学号"));
ui->tableWidget->setHorizontalHeaderItem(1, new QTableWidgetItem("姓名"));
ui->tableWidget->setHorizontalHeaderItem(2, new QTableWidgetItem("年龄"));
// 我们也可以设置垂直方向的表头!
// 给表格中添加元素
ui->tableWidget->setItem(0, 0, new QTableWidgetItem("1001"));
ui->tableWidget->setItem(0, 1, new QTableWidgetItem("张三"));
ui->tableWidget->setItem(0, 2, new QTableWidgetItem("20"));
ui->tableWidget->setItem(1, 0, new QTableWidgetItem("1002"));
ui->tableWidget->setItem(1, 1, new QTableWidgetItem("李四"));
ui->tableWidget->setItem(1, 2, new QTableWidgetItem("19"));
ui->tableWidget->setItem(2, 0, new QTableWidgetItem("1003"));
ui->tableWidget->setItem(2, 1, new QTableWidgetItem("王五"));
ui->tableWidget->setItem(2, 2, new QTableWidgetItem("20"));
}
3.编写按钮的 slot 函数
cpp
void Widget::on_pushButton_insertRow_clicked()
{
// 需要知道当前一共有多少行
int rowCount = ui->tableWidget->rowCount();
// 在最后一行之后进行新增行 --- 注意此处的参数是"下标",表示你新增之后的这一行是第几行
ui->tableWidget->insertRow(rowCount);
}
void Widget::on_pushButton_deleteRow_clicked()
{
// 获取到选中的行号
int curRow = ui->tableWidget->currentRow();
// 删除这一行
ui->tableWidget->removeRow(currRow);
}
void Widget::on_pushButton_insertColumn_clicked()
{
// 先获取到一共有几行
int columunCount = ui->tableWidget->columnCount();
// 在对应的位置新增这一列
ui->tableWidget->insertColumn(columunCount);
// 设置列名 -- 重重输入框中获取到
const QString& text = ui->lineEdit->text();
ui->tableWidget->setHorizontalHeaderItem(columunCount,new QTableWidgetItem(text));
}
void Widget::on_pushButton_4_clicked()
{
// 获取到选中的列
int curCol = ui->tableWidget->currentColumn();
//删除这一列
ui->tableWidget->removeColumn(curCol);
}
4.执行程序, 即可完成表格的基本操作.
默认情况下, 单元格中的内容直接就是可编辑的. 如果不想让用户编辑, 可以设置:
ui->tablewidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
Tree Widget
使用 QTreewWidget 表示一个树形控件. 里面的每个元素, 都是一个 QTreewWidgetItem ,每个QTreeWidgetItem 可以包含多个文本和图标, 每个文本/图标为一个 列.
可以给 QTreeWidget 设置顶层节点(顶层节点可以有多个), 然后再给顶层节点添加子节点, 从而构成树形结构.
QTreeWidget 控件虽然是树形结构,但是这个树形结构没有体现出根节点,是从根节点的下一层 --- 子节点,开始计算的!

对于顶层节点来说,就可以看成是"List"这样的结构!
我们可以看成是 QTableWidget 的进化版本!
QTreewidget 核心方法(针对顶层节点)
方法 | 说明 |
---|---|
clear | 清空所有子节点 |
addTopLevelItem(QTreeWidgetItem* item) | 新增顶层节点 |
topLevelItem(int index) | 获取指定下标的顶层节点 |
topLevelItemCount() | 获取顶层节点个数 |
indexOfTopLevelItem(QTreeWidgetItem* item) | 查询指定节点是顶层节点中的下标 |
takeTopLevelItem(int index) | 删除指定的顶层节点,返回QTreeWidgetItem* 表示被删除的元素 |
currentItem() | 获取到当前选中的节点,返回QTreeWidgetItem* |
setCurrentItem(QTreeWidgetItem* item) | 选中指定节点 |
setExpanded(bool) | 展开/关闭节点 |
setHeaderLabel(const QString& text) | 设置 TreeWidget 的 header 名称 --- 这才是根节点,设置名字的! |
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 | 是否禁用 |
expand | 是否展开 |
sizeHint | 尺寸大小 |
selected | 是否选中 |
QTreeWidgetItem 核心方法(新增子节点)
方法 | 说明 |
---|---|
addChild(QTreeWidgetItem* child) | 新增子节点 |
childCount() | 子节点的个数 |
child(int index) | 获取指定下标的子节点, 返回 QTreeWidgetItem* |
takeChild(int index) | 删除对应下标的子节点 |
removeChild(QTreeWidgetItem* child) | 删除对应的子节点 |
parent() | 获取该元素的父节点 |
代码示例: 使用 QTreeWidget
1.在界面上创建一个 TreeView , 右键 => 变形为 => Treewidget , 再创建一个 lineEdit 和 两个按钮
注意: TreeWidget 是 TreeView NFA, 功能比 TreeView 更丰富. 咱们使用 Treewidget 即可!
2.编写代码, 构造初始数据(我们也可以通过图形化界面编辑)
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置根节点的名字
ui->treeWidget->setHeaderLabel("动物");
// 新增顶层节点
QTreeWidgetItem* item1 = new QTreeWidgetItem();
// 每一个节点后可以设置多个列,此处为了简单就只设置了一列了!
item1->setText(0,"猫");
// 添加到顶层节点中
ui->treeWidget->addTopLevelItem(item1);
// 新增顶层节点
QTreeWidgetItem* item2 = new QTreeWidgetItem();
// 每一个节点后可以设置多个列,此处为了简单就只设置了一列了!
item2->setText(0,"狗");
// 添加到顶层节点中
ui->treeWidget->addTopLevelItem(item2);
// 新增顶层节点
QTreeWidgetItem* item3 = new QTreeWidgetItem();
// 每一个节点后可以设置多个列,此处为了简单就只设置了一列了!
item3->setText(0,"鸟");
// 添加到顶层节点中
ui->treeWidget->addTopLevelItem(item3);
// 添加一些子节点
QTreeWidgetItem* item4 = new QTreeWidgetItem();
item4->setText(0, "中华田园猫");
item1->addChild(item4);// 添加到顶层节点
QTreeWidgetItem* item5 = new QTreeWidgetItem();
item5->setText(0, "布偶猫");
item1->addChild(item5);// 添加到顶层节点
QTreeWidgetItem* item6 = new QTreeWidgetItem();
item6->setText(0, "暹罗猫");
item1->addChild(item6);// 添加到顶层节点
}
3.编写代码, 实现按钮的 slot 函数
cpp
void Widget::on_pushButton_insertTopLevelItem_clicked()
{
// 获取输入框中的内容
const QString& text = ui->lineEdit->text();
// 构造一个 QTreeWidgetItem 出来
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, text);
// 添加到顶层节点中
ui->treeWidget->addTopLevelItem(item);
}
void Widget::on_pushButton_insertItem_clicked()
{
// 获取到当前选中的节点
QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
if(currentItem == nullptr)
{
return;
}
// 获取到输入框中的内容
const QString& text = ui->lineEdit->text();
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, text);
// 插入到选中节点的子结点中
currentItem->addChild(item);
}
void Widget::on_pushButton_3_clicked()
{
// 获取到选中的元素
QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
if(currentItem == nullptr)
{
return;
}
// 删除选中的元素,需要先获取到父元素
QTreeWidgetItem* parent = currentItem->parent();
if(parent == nullptr)
{
// 顶层元素
int index = ui->treeWidget->indexOfTopLevelItem(currentItem);
ui->treeWidget->takeTopLevelItem(index);
}
else
{
// 普通元素
parent->removeChild(currentItem);
}
}
4.执行程序, 可以针对树形框进行编辑.

上述这几个控件相关的操作,数据都是在内从中保存的,无论在界面上做任何操作,重启运行程序,之前的数据就没有了
如果想让数据能够重启也不丢失,就需要编写更多的代码,把内存存储的数据获取到,写入到文件中,并且在下次运行的时候。从文件中加载数据!