每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry”
绪论:
本章将通过代码示例详细介绍了Qt中QListWidget、QTableWidget和QTreeWidget三种多元素控件的使用方法与核心功能,涵盖列表的增删操作、表格的行列管理以及树形结构的节点处理。
————————
早关注不迷路,话不多说安全带系好,发车啦(建议电脑观看)。
多元素控件
Qt 中提供的多元素控件有:
- QListWidget
- QListView(前两个表示列表结构)
- QTableWidget
- QTableView(前两个表示表格结构)
- QTreeWidget
- QTreeView(前两个表示树形结构)
不难发现两种结构中有:xxWidget 和 xxView 之间的区别
- xxView 是更底层的实现
- xxWidget 是基于 xxView 封装起来的
例如:
- QTableView 是基于 MVC 设计的控件
- QTableView ⾃⾝不持有数据(不支持Model)。使⽤ QTableView 的时候需要⽤⼾创建⼀个 Model 对象 (⽐如 QStandardModel ),比较麻烦~
- 并且把 Model 和 QTableView 关联起来. 后续修改 Model 中的数据就会影响 QTableView 的显⽰
- 修改 QTableView 的显⽰也会影响到 Model 中的数据(双向绑定).
- QTableWidget 则是 QTableView 的⼦类, 对 Model 进⾏了封装
- 所以不需要⽤⼾⼿动创建 Model 对象, 直接就可以往 QTableWidget 中添加数据了
- 提供了更方便的 api 让自己使用
不能说谁好谁坏,不同场景使用不同:
- 其中 xxxWidget 使用起来比较方便,但功能有限
- 而 xxxView 使用起来比较麻烦,但可以自由diy,实现更复杂的功能
因为他们是两两一组的,所以此处就着重讲解Widget
List Widget 多元素控件 列表
使⽤ QListWidget 能够显⽰⼀个纵向的列表. 形如:
核⼼属性
属性 | 说明 |
---|---|
currentRow | 当前被选中的是第⼏⾏ |
count | ⼀共有多少⾏ |
sortingEnabled | 是否允许排序 |
isWrapping | 是否允许换⾏ |
itemAlignment | 元素的对⻬⽅式 |
selectRectVisible | 被选中的元素矩形(高亮)是否可⻅ |
spacing | 元素之间的间隔 |
核⼼⽅法
⽅法 | 说明 |
---|---|
addItem(const QString& label) addItem(QListWidgetItem *item) |
列表中添加元素(列表中的每个元素/每一项就成为一个item(通过QListWidgetItem 类表示)) |
currentItem() | 返回 QListWidgetItem* 表⽰当前选中的元素 |
setCurrentItem(QListWidgetItem* item) | 设置选中哪个元素 |
setCurrentRow(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) | ⿏标进⼊元素时触发 |
当选错了多元素控件的时候,可以通过右键选择 “变型为” 进行修改:
实操:ListWidget的新增删除列表
初始化默认的值
- 直接在构造函数中
- 通过列表控件调用addItem接口
- 添加:C++、Java、Python 子元素
- 也能直接在图形化界面中的右击 “列表控件” 选择 “编辑项目” 进行添加
- 直接在构造函数中
给新增按钮添加点击信号的槽函数:
- 获取到输入框中的内容
- 将获取到的内容 添加到QListWidget中
给删除按钮添加点击信号的槽函数:
- 获取被选元素它的行号(
currentRow
) - 按行号进行删除元素
takeitem
- 获取被选元素它的行号(
右键列表新增
currentItemChanged
信号的槽函数(需要添加头文件 QListWidgetItem):- 通过这个槽函数感知变化
- 判断current是否为空,不为空则打印:当前选中元素的文本
- 并且判断 previous 不为空的话也进行打印文本
结果:
源码:
#include "widget.h"
#include "ui_widget.h"
#include <QListWidget>
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//添加子元素 addItem
ui->listWidget->addItem("C++");
ui->listWidget->addItem("Java");
ui->listWidget->addItem("Python");
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//获取label内部的数据
QString text = ui->lineEdit->text();
//添加到list中
ui->listWidget->addItem(text);
}
void Widget::on_pushButton_2_clicked()
{
//获取鼠标选中的行号
int row = ui->listWidget->currentRow();
//删除行号的内容 takeitem
ui->listWidget->takeItem(row);
}
void Widget::on_listWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous)
{
if(previous != nullptr){
qDebug() << "previous: "<< previous->text();
}
//current 表示当前选中的元素、previous表示选中这个元素之前选择的元素
if(current != nullptr){
qDebug() << "current: "<< current->text();
}
}
Table Widget
使⽤ QTableWidget 表⽰⼀个表格控件. ⼀个表格中包含若⼲⾏, 每⼀⾏⼜包含若⼲列. 表格中的每个单元格, 是⼀个 QTableWidgetItem 对象
QTableWidget 核⼼⽅法
⽅法 | 说明 |
---|---|
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&) | 设置字体 |
实操:简单实现表格增加行/列,添加元素
使用ui构建,如上图
编辑框初始化:
- 新增列:学号、姓名、年龄
- 新增行:1、2、3
- 1 张三 20、…
代码初始化:
- 创建三行(
insertRow
) - 创建三列(
insertColumn
) - 给3个列设定列名:
setHeorizontalHeaderItem
- 给表格中添加数据
setItem
(行,列,QTableWidgetItem(数据))
- 创建三行(
初始化的值:
给按钮添加槽函数:
- 给新增一行按钮添加槽函数
- 获取多少行
rowCount
- 在最后一行之后新增新行
insertRow(rowCount)
(注意此处是下标,表示你新增之后的这是第几行)
- 获取多少行
- 删除选中行
- 获取选中的行号
currentRow
- 删除这一行
removeRow
- 获取选中的行号
- 新增行
- 获取有几列
columnCount
- 新增一列
insertColumn
- 设置列名(从输入框中获取)
- 获取输入框的文本
- 给新增行添加列名
setHorizontalHeaderItem
- 获取有几列
- 删除选中列
- 获取选中列号
currentColumn
- 删除这一列
removeColumn
- 获取选中列号
源码:
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//新增行
ui->tableWidget_2->insertRow(0);//默认的即可不用设置行名称
ui->tableWidget_2->insertRow(1);
ui->tableWidget_2->insertRow(2);
//新增列
ui->tableWidget_2->insertColumn(0);
ui->tableWidget_2->setHorizontalHeaderItem(0,new QTableWidgetItem("学号"));
ui->tableWidget_2->insertColumn(1);
ui->tableWidget_2->setHorizontalHeaderItem(1,new QTableWidgetItem("姓名"));
ui->tableWidget_2->insertColumn(2);
ui->tableWidget_2->setHorizontalHeaderItem(2,new QTableWidgetItem("年龄"));
//添加数据
ui->tableWidget_2->setItem(0,0,new QTableWidgetItem("1"));
ui->tableWidget_2->setItem(0,1,new QTableWidgetItem("张三"));
ui->tableWidget_2->setItem(0,2,new QTableWidgetItem("20"));
ui->tableWidget_2->setItem(1,0,new QTableWidgetItem("2"));
ui->tableWidget_2->setItem(1,1,new QTableWidgetItem("李四"));
ui->tableWidget_2->setItem(1,2,new QTableWidgetItem("28"));
ui->tableWidget_2->setItem(2,0,new QTableWidgetItem("3"));
ui->tableWidget_2->setItem(2,1,new QTableWidgetItem("王五"));
ui->tableWidget_2->setItem(2,2,new QTableWidgetItem("88"));
}
Widget::~Widget()
{
delete ui;
}
//新增一列
void Widget::on_pushButton_clicked()
{
//获取LineEdit中的文本
QString text = ui->lineEdit->text();
//获取当前列数
int ccount = ui->tableWidget->columnCount();
//添加新列
ui->tableWidget->insertColumn(ccount);//添加的是下标,所以刚好和个数相同
//添加列名称
if(text != nullptr){
ui->tableWidget->setHorizontalHeaderItem(ccount,new QTableWidgetItem(text));
}
}
//删除选择的列
void Widget::on_pushButton_2_clicked()
{
//获取光标选中的列
int ccolumn = ui->tableWidget->currentColumn();
//删除
ui->tableWidget->removeColumn(ccolumn);
}
//新增一行
void Widget::on_pushButton_3_clicked()
{
//获取LineEdit中的文本
QString text = ui->lineEdit->text();
//获取当前行数
int rcount = ui->tableWidget->rowCount();
//添加新行
ui->tableWidget->insertRow(rcount);//添加的是下标,所以刚好和个数相同
//添加行名称
if(text != ""){
ui->tableWidget->setVerticalHeaderItem(rcount,new QTableWidgetItem(text));
}
}
//删除选中的行
void Widget::on_pushButton_4_clicked()
{
//获取光标选中的行
int crow = ui->tableWidget->currentRow();
//删除行
ui->tableWidget->removeRow(crow);
}
Tree Widget
使⽤ QTreeWidget 表⽰⼀个树形控件。⾥⾯的每个元素, 都是⼀个 QTreeWidgetItem ,每个
QTreeWidgetItem 可以包含多个⽂本和图标,每个⽂本/图标为⼀个 列。可以给 QTreeWidget 设置顶层节点(顶层节点可以有多个), 然后再给顶层节点添加⼦节点, 从⽽构成树形结构。
对于列数的使用,可以对某子元素进行数据的展示,例如下图的 猫2 列,可以改成猫的年龄/体重,来描述当前子元素的各种属性数据
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控件虽然是树形结构,但是这个树形结构没有根节点,是从根结点的下一层结点开始计算的(如下图),所以是新增顶层结点
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() | 获取该元素的⽗节点 |
实操:理解顶层元素和子元素的添加删除
通过界面编辑快速填充初始值
代码操作:
- 拖拽一个treeWidget
- 设置根节点的名字
setHeaderLabel
- 新增顶层结点
- 创建
QTreeWidgetItem
结点对象 - 每个结点都可以设置多个列名称
setText
(列数(从0开始),名称猫、狗、鸟) - 添加到顶层结点中,
addTopLevelItem
- 创建
- 再添加
猫
的子节点- 写创建 结点对象,设置名称(列数,中华田园猫、布偶猫、…)
- 添加到item1中的子节点 addChild
三个按钮的槽函数
- 插入顶层结点按钮添加点击信号的槽函数
- 获取输入框中的内容
- 构造一个节点对象,设置名称
setText
将获取到的内容给到 - 添加到顶层结点中
- 插入子节点
- 获取当前选中节点对象 currentItem(若为空则啥也不做返回…)
- 获取输入框中的内容
- 构造一个节点对象,
- 设置名称
setText
将获取到的内容给到(同上12不变) - 插入到选中结点的子节点中
- 删除选中的元素
- 获取选中元素
- 非空则删除选中元素,需要先获取父元素,通过父元素进行删除 parent
- 若为空则代表为顶层元素
- 获取顶层元素下标
indexOfTopLevelItem
- 从控件中删除顶层结点,
takeTopLevelItem
- 获取顶层元素下标
- 非空则为普通元素,则通过获取的获取的parent删除子结点
removeChild
结果:
#include "widget.h"
#include "ui_widget.h"
#include <QTreeWidgetItem>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置根节点名称
ui->treeWidget->setHeaderLabel("1");
//创建结点对象
QTreeWidgetItem* item1 = new QTreeWidgetItem();
item1->setText(0,"猫");
ui->treeWidget->addTopLevelItem(item1);
//给顶层元素添加子元素
QTreeWidgetItem* citem1 = new QTreeWidgetItem();
citem1->setText(0,"狸花猫");
item1->addChild(citem1);
//就不多添加了...
QTreeWidgetItem* item2 = new QTreeWidgetItem();
item2->setText(0, "狗");
ui->treeWidget->addTopLevelItem(item2);
QTreeWidgetItem* item3 = new QTreeWidgetItem();
item3->setText(0, "⻦");
ui->treeWidget->addTopLevelItem(item3);
}
Widget::~Widget()
{
delete ui;
}
//添加顶层元素
void Widget::on_pushButton_clicked()
{
//获取输入框内容
QString text = ui->lineEdit->text();
if(text == QString()){
text = "默认值...";
}
//将内容创建项目
QTreeWidgetItem* item = new QTreeWidgetItem();
item->setText(0,text);
//添加到顶层
ui->treeWidget->addTopLevelItem(item);
}
//添加选中的子元素
void Widget::on_pushButton_2_clicked()
{
//获取当前选中的顶层元素
QTreeWidgetItem* item = ui->treeWidget->currentItem();
if(item == nullptr) return ;
//获取输入框内容
QString text = ui->lineEdit->text();
if(text == QString()){
text = "默认值...";
}
//将输入框内容添加到创建的新子元素中
QTreeWidgetItem* citem = new QTreeWidgetItem();
citem->setText(0,text);
//给顶层添加新元素
item->addChild(citem);
}
//删除选中的节点
void Widget::on_pushButton_3_clicked()
{
//获取当前选中的节点
QTreeWidgetItem* item = ui->treeWidget->currentItem();
//需要获取父元素,通过父元素进行删除
QTreeWidgetItem* pitem = item->parent();
//若为空则,此时已经是顶层元素
if(pitem == nullptr){
//获取指定节点的顶层元素的下标
int index = ui->treeWidget->indexOfTopLevelItem(item);
ui->treeWidget->takeTopLevelItem(index);
}
else{ //若不是则:
//通过获取的父元素,删除指定的子元素
pitem->removeChild(item);
}
}
注意上述控件相关的操作,数据都是在内存中的,重新运行程序数据就没了
本章完。预知后事如何,暂听下回分解。
如果有任何问题欢迎讨论哈!
如果觉得这篇文章对你有所帮助的话点点赞吧!
持续更新大量C++细致内容,早关注不迷路。