一、多元素控件
Qt中提供的多元素控件有:QListWidget、QListView、QTableWidget、QTableView、QTreeWidget和QTreeView
XXWidget和XXView的区别
以 QTableWidget 和 QTableView 为例
- QTableView 是采用 MVC 设计模式的控件,其本身并不存储数据。使用时需要用户创建一个 Model 对象(例如 QStandardModel),并将该 Model 与 QTableView 进行关联。这种关联实现了双向绑定:修改 Model 中的数据会同步更新 QTableView 的显示内容,反之,通过 QTableView 修改显示内容也会自动更新 Model 中的数据。
- QTableWidget 是 QTableView 的子类,它封装了 Model 功能。用户无需手动创建 Model 对象,可以直接向 QTableWidget 中添加数据。
二、QListWidget
使用 QListWidget 能够显示⼀个纵向的列表,每个选项都可以被选中
| 属性 | 说明 |
|---|---|
| currentRow | 当前被选中的是第几行 |
| count | 一共有多少行 |
| sortingEnabled | 是否允许排序 |
| isWrapping | 是否运行换行 |
| itemAlignment | 元素的对齐方式 |
| selectRectVisible | 被选中的元素矩形是否可见 |
| spacing | 元素之间的间隔 |
核心方法
| 方法 | 说明 |
|---|---|
| addItem(const QString& label)、addItem(QListWidgetItem *item) | 列表中添加元素 |
| currentItem() | 返回 QListWidgetItem* 表示当前选中的元素 |
| setCurrentItem(QListWidgetItem* item) | 设置选中哪个元素 |
| setCurrentRow(int row) | 设置选中第几行的元素 |
| insertItem(const QString& label, int row) 、insertItem(QListWidgetItem *item, introw) | 在指定的位置插入元素 |
| 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中的一个元素,本质上就是"文本+图标"构成的
| 方法 | 说明 |
|---|---|
| setFont | 设置字体 |
| setIcon | 设置图标 |
| setHidden | 设置隐藏 |
| setSizeHint | 设置尺寸 |
| setSelected | 设置是否被选中 |
| setText | 设置文本 |
| setTextAlignment | 设置文本对齐方式 |
代码样例(使用ListWidget):
首先,在界面上创建⼀个 ListView , 右键 => 变形为 => ListWidget , 再创建⼀个 lineEdit 和 两个按钮

编写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("C");
}
编写listWidget的槽函数,需要注意,两个指针初识情况下是没有选中的,就会导致两个指针指向的是NULL
cpp
void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
if(current != NULL && previous != NULL)
{
qDebug() << "当前被选中: " << current->text() << " 之前选择: " << previous->text();
}
}
上述代码主要要包含头文件

编写按钮的槽函数
cpp
void Widget::on_pushButton_add_clicked()
{
//获取输入框中的数据
const QString& text = ui->lineEdit->text();
if(text.isEmpty())
{
return;
}
ui->listWidget->addItem(text);
}
void Widget::on_pushButton_sub_clicked()
{
//获取当前被选中的元素
int row = ui->listWidget->currentRow();
//删除这一行
ui->listWidget->takeItem(row);
}
运行代码:

三、QTableWidget
QTableWidget 用于显示表格控件。该表格由多行组成,每行包含若干列。每个单元格对应一个 QTableWidgetItem 对象。
核心方法
| 方法 | 说明 |
|---|---|
| item(int row, int column) | 根据行数列数获取指定的 QTableWidgetItem* |
| setItem(int row, int column,QTableWidget*) | 根据行数列数设置表格中的元素 |
| 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, QTableWidget*) | 设置指定列的表头 |
| setVerticalHeaderItem(int row,QTableWidget*) | 设置指定行的表头 |
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):
首先,在界面上创建一个QTableWidget和四个按钮,一个输入框。

编写widget.cpp
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建3行
ui->tableWidget->insertRow(0);
ui->tableWidget->insertRow(1);
ui->tableWidget->insertRow(2);
//创建3列
ui->tableWidget->insertColumn(0);
ui->tableWidget->insertColumn(1);
ui->tableWidget->insertColumn(2);
//给3列设定列名
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("18"));
ui->tableWidget->setItem(1, 0, new QTableWidgetItem("1002"));
ui->tableWidget->setItem(1, 1, new QTableWidgetItem("李四"));
ui->tableWidget->setItem(1, 2, new QTableWidgetItem("20"));
ui->tableWidget->setItem(2, 0, new QTableWidgetItem("1003"));
ui->tableWidget->setItem(2, 1, new QTableWidgetItem("王五"));
ui->tableWidget->setItem(2, 2, new QTableWidgetItem("19"));
//如果不想要用户编辑单元格
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
}
设置槽函数
cpp
void Widget::on_pushButton_add_row_clicked()
{
//获取行数
int rowCount = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(rowCount);
}
void Widget::on_pushButton_delete_row_clicked()
{
//获取选中的行号
int row = ui->tableWidget->currentRow();
ui->tableWidget->removeRow(row);
}
void Widget::on_pushButton_add_col_clicked()
{
//获取列数
int colCount = ui->tableWidget->columnCount();
ui->tableWidget->insertColumn(colCount);
//从文本中获取列名
const QString& name = ui->lineEdit->text();
ui->tableWidget->setHorizontalHeaderItem(colCount, new QTableWidgetItem(name));
}
void Widget::on_pushButton_delete_col_clicked()
{
int col = ui->tableWidget->currentColumn();
ui->tableWidget->removeColumn(colorCount());
}
运行代码:

四、QTreeWidget
使用 QTreeWidget 可以创建树形控件。每个元素都是 QTreeWidgetItem 对象,这些对象可以包含多列文本和图标数据。
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) | 元素被展开时触发 |
| itemCollapsend(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):
首先,在界面上创建⼀个 TreeView , 右键 => 变形为 => TreeWidget , 再创建⼀个 lineEdit 和 三个按钮

编写widget.cpp文件
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);
}
编写槽函数
cpp
void Widget::on_pushButton_addTopElement_clicked()
{
//获取输入框内容
const QString& text = ui->lineEdit->text();
if(text.isEmpty())
{
return ;
}
//将获取的内容插入顶层节点
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0, text);
ui->treeWidget->addTopLevelItem(item);
}
void Widget::on_pushButton_addSelectElement_clicked()
{
//获取输入框内容
const QString& text = ui->lineEdit->text();
if(text.isEmpty())
{
return ;
}
//获取当前选中的节点
QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
if(currentItem == NULL)
{
return;
}
//构造新的item
QTreeWidgetItem* newItem = new QTreeWidgetItem();
newItem->setText(0, text);
//添加新的item到选中节点中
currentItem->addChild(newItem);
//展开父节点
currentItem->setExpanded(true);
}
void Widget::on_pushButton_deleteElement_clicked()
{
//获取当前选中节点
QTreeWidgetItem* currentItem = ui->treeWidget->currentItem();
if(currentItem == NULL)
{
return ;
}
//获取当前节点的父节点
QTreeWidgetItem* parent = currentItem->parent();
if(parent == NULL)
{
//为顶层节点
int index = ui->treeWidget->indexOfTopLevelItem(currentItem);
ui->treeWidget->takeTopLevelItem(index);
}
else
{
//不是顶层节点
parent->removeChild(currentItem);
}
}
运行代码:

五、QGroupBox
使用 QGroupBox 创建带标题的分组框,可将相关控件归为一组显示,使界面布局更加美观清晰。
核心属性
| 属性 | 说明 |
|---|---|
| title | 分组框标题 |
| alignment | 分组框内部内容对齐方式 |
| flat | 是否是"扁平"模式 |
| checkable | 是否可选择:设为 true, 则在 title 前方会多出⼀个可勾选的部分 |
| checked | 描述分组框的选择状态 (前提是 checkable 为 true) |
注意:分组框主要用于界面美化,不涉及用户交互和业务逻辑,属于锦上添花的组件。
代码样例(给麦当劳样例加上分组框):
首先,在界面上创建三个分组框, 并且在分组框内部创建下拉框和微调框

编写widget.cpp文件
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
ui->comboBox->addItem("巨⽆霸");
ui->comboBox->addItem("⻨辣鸡腿堡");
ui->comboBox_2->addItem("薯条");
ui->comboBox_2->addItem("⻨辣鸡翅");
ui->comboBox_3->addItem("可乐");
ui->comboBox_3->addItem("雪碧");
}
运行程序:

六、QTabWidget
使用 QTabWidget 创建带标签页的控件,可向其中添加多个 widget,通过切换标签页来展示不同内容。
核心属性
| 属性 | 说明 |
|---|---|
| tabPosition | 标签页所在的位置: North 上方、South 下方、 West 左侧、East 右侧 |
| currentIndex | 当前选中了第几个标签页 (从 0 开始计算) |
| currentTabText | 当前选中的标签页的文本 |
| currentTabName | 当前选中的标签页的名字 |
| currentTabIcon | 当前选中的标签页的图标 |
| currentTabToolTip | 当前选中的标签页的信息 |
| tabsCloseable | 标签页是否可以关闭 |
| movable | 标签页是否可以移动 |
核心信号
| 信号 | 说明 |
|---|---|
| currentChanged(int) | 在标签页发生切换时触发, 参数为被点击的选项卡编号 |
| tabBarClicked(int) | 在点击选项卡的标签条的时候触发. 参数为被点击的选项卡编号 |
| tabBarDoubleClicked(int) | 在双击选项卡的标签条的时候触发. 参数为被点击的选项卡编号 |
| tabCloseRequest(int) | 在标签页关闭时触发. 参数为被关闭的选项卡编号. |
代码样例(使用标签页管理多组控件):
首先,在界面上创建⼀个 QTabWidget , 和两个按钮

注意:QTabWidget 中的每个标签页都是一个独立的 QWidget 组件:
- 点击标签即可快速切换页面
- 右键点击 QTabWidget 可进行添加或删除标签页操作
编写widget.cpp文件,注意新创建的 label 的父元素, 是 ui->tab 和 ui->tab_2 . Qt 中使用父子关系决定该控件 "在哪里".
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QLabel* label = new QLabel(ui->tab);
label->setText("标签一");
label->resize(100, 50);
QLabel* label2 = new QLabel(ui->tab_2);
label2->setText("标签二");
label2->resize(100, 50);
}
编写槽函数
cpp
void Widget::on_pushButton_add_clicked()
{
//获取当前有几个标签
int count = ui->tabWidget->count();
//创建新的widget
QWidget* w = new QWidget();
ui->tabWidget->addTab(w, QString("Tab") + QString::number(count + 1));
//给新添加的widget设置label
QLabel* label = new QLabel(w);
label->setText(QString("标签") + QString::number(count + 1));
label->resize(100, 50);
//选中新标签
ui->tabWidget->setCurrentIndex(count);
}
void Widget::on_pushButton_del_clicked()
{
//获取当前标签下标
int index = ui->tabWidget->currentIndex();
//删除这个标签
ui->tabWidget->removeTab(index);
}
void Widget::on_tabWidget_currentChanged(int index)
{
qDebug() << "当前选中标签⻚为: " << index;
}
运行代码:

如果不想按按钮删除可以勾选QTabWidget中的tabsClosable

