【Qt6】列表模型——几个便捷的列表类型
前面一些文章,老周简单介绍了在Qt 中使用列表模型的方法。很明显,使用 Item Model 在许多时候还是挺麻烦的——要先建模型,再放数据,最后才构建视图。为了简化这些骚操作,Qt 提供了几个便捷类。今天咱们逐个看看。
一、QListWidget
这厮对应的 List View,用来显示简单的列表。要添加列表项,此类有两个方法
void addItem(const QString &label) ;
void addItem(QListWidgetItem *item); void addItems(const QStringList &labels);
前两个方法是调用一次就添加一个列表项,新加的列表项将追加到列表末尾;addItems 方法是一次性添加多个项,以字符串列表的方式添加。
对于简单的列表项,可以用第一个方法,直接传个字符串就完事了。第二个方法需要一个 QListWidgetItem 对象,它可以对列表项做一些其他设置,如放个图标,文本对齐方式等。当然,如果你不想用追加模式添加列表项,也可以用插入方法:
void insertItem(int row, const QString &label);
void insertItem(int row, QListWidgetItem *item);
void insertItems(int row, const QStringList &labels);
和 addItem 方法一样,但多了一个 row 参数。因为简单的列表模型只有一个列,所以 row 就是子项的索引。索引从 0 起计算,指定 row 参数表示在此处插入列表项,而列表中原有的元素会向后移一位。比如 5、6、7,在row=1 处插入9,即列表变成 5、9、6、7。
要删除列表项,调用 takeItem 方法。
QListWidgetItem* takeItem(int row)
调用后,指定索引处的项被移除,并返回该项的实例引用(指针类型)。不要调用 removeItemWidget 方法,那个只删除用于显示列表项的组件罢了,列表项并未真正删除。
下面咱们动动手,做个练习。
int main(int argc, char **argv)
{
QApplication app(argc, argv);
// 实例化组件
QListWidget *view = nullptr;
view = new QListWidget;
// 窗口标题
view->setWindowTitle("烧烤档常见食物");
// 窗口大小
view->resize(255, 200);
// 添加点子项
view->addItem("烤羊肺");
view->addItem("烤年糕");
// 选创建QListWidgetItem实例,再添加
QListWidgetItem* item = new QListWidgetItem("烤狗腿");
view->addItem(item);// 也可以用字符串列表
QStringList strs;
strs << "臭豆腐" << "烤鸭肉" << "烤鸡翅";
view->addItems(strs); // 显示窗口
view->show();
// 进入事件循环
return QApplication::exec();
}
第一、二项直接用字符串添加列表项;第三项是先创建 QListWidgetItem 实例,然后再添加;第四、五、六项是通过字符串列表一次性添加的。QStringList 其实就是 QList<QString> 类。
效果如下图所示:
前面我们提到过一个 removeItemWidget 方法。提到它就得提一下 setItemWidget 方法,因为这俩是青梅竹马的。这一对方法的作用是为某个列表项添加(或删除)一个自定义组件(QWidget 或其子类)。被添加的组件会显示在该列表项上面——其实是覆盖在原有内容上面的。这个方法虽然方便我们为列表项定制 UI,但它不支持动态行为,比如,你如果加一个文本框用来编辑数据,编辑好后数据是不会自动保存的,所有的逻辑都要你自己写代码实现。
咱们拿上面的示例开刀,为最后三项加入个按钮,看看会怎样。代码修改如下:
// 获取最后三项的引用
int len = view->count(); // 猜猜它返回什么
QListWidgetItem* tmpItem1 = view->item(len - 3);
QListWidgetItem* tmpItem2 = view->item(len - 2);
QListWidgetItem* tmpItem3 = view->item(len - 1);
// 弄三个按钮
QPushButton* b1 = new QPushButton;
b1->setText("A");
QPushButton* b2= new QPushButton;
b2->setText("B");
QPushButton* b3 = new QPushButton;
b3->setText("C");
// 调整一下列表项的高度,不然按钮可能显示不全
QSize size(0, 32);
tmpItem1->setSizeHint(size);
tmpItem2->setSizeHint(size);
tmpItem3->setSizeHint(size);
// 设置三个按钮与三个列表项关联
view->setItemWidget(tmpItem1, b1);
view->setItemWidget(tmpItem2, b2);
view->setItemWidget(tmpItem3, b3);
// 为了能发现其中的秘密,咱们让按钮的宽度缩小一点
b1->setFixedWidth(25);
b2->setFixedWidth(25);
b3->setFixedWidth(25);
setSizeHint 方法为项目的“期望”大小设置一个固定的高度,宽度为0表示由布局行为决定;而 32 是高度,告诉容器组件:“我需要32的高度”,毕竟默认的高度可能显示不全按钮。最后,我用 setFixedWidth 方法把三个按钮的宽度给固死了,它的宽度只能是25像素。这么做是为了让大伙看清楚,我们自定义的组件其实就是显示在原有列表项上面的。如下图,你看看,原列表项的文本还在呢。
不过,上述代码只是方便理解,没什么实际用处。下面咱们做有用的,重新做一下这个示例。
view->connect(view, &QListWidget::currentItemChanged, [=]
(QListWidgetItem* current, QListWidgetItem* previous) -> void{
// 删除前一个列表项所关联的QWidget
if(previous)
{
view->removeItemWidget(previous);
// 还原列表项高度
previous->setSizeHint(QSize(-1, -1));
}
// 如当前项为NULL,那后面的代码就没必要运行了
if(!current){
return;
}
// 为当前项创建QWidget
QWidget* wg = new QWidget;
// 设置背景色
wg->setAutoFillBackground(true);
wg->setStyleSheet("background: lightgray");
// 布局
QHBoxLayout* layout=new QHBoxLayout;
wg->setLayout(layout);
// 标签
QLabel* lb=new QLabel;
// 标签的文本就是列表项的文本
lb->setText(current->text());
layout->addWidget(lb);
// 加个空白,填补剩余空间
layout->addStretch(1);
// 按钮
QPushButton* btn= new QPushButton("删除");
layout->addWidget(btn);
// 套娃,又一个信号连接
QObject::connect(btn, &QPushButton::clicked, [=](){
// 当前索引
int row = view->row(current);
// 把当前列表项分离出来
QListWidgetItem* _oldItem = view->takeItem(row);
// 清除它
delete _oldItem;
});
// 要改一下列表项的高度,不然按钮可能显示不全
current->setSizeHint(QSize(0, 40));
// 关联列表项与组件
view->setItemWidget(current, wg);
});
这里实现的逻辑是:当列表项被选中才显示按钮。现在咱们也知道,setItemWidget 是创建一个自定义组件覆盖在列表项上的,所以,在列表项选中后,显示的自定义组件的背景不能透明,不然就穿帮了。组件里面放一个QLabel 组件显示列表项的文本,然后再放一个“删除”按钮,这样就差不多了。
需要用到 QListWidget 的一个信号:
void currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
这个信号正符合咱们的需求,current 表示当前项(99.9% 的情况下就是被选中的项),previous 是前一个项——即被取消选择的项。有了这两个参数,咱们就可以用 removeItemWidget 方法删除 previous 关联的 Widget,并为 current 关联新的 Widget。
currentItemChanged 信号连接的 lambda 表达式内部又嵌套了一个 lambda 表达式—— 连接按钮的 clicked 信号。
QObject::connect(btn, &QPushButton::clicked, [=](){
// 当前索引
int row = view->row(current);
// 把当前列表项分离出来
QListWidgetItem* _oldItem = view->takeItem(row);
// 清除它
delete _oldItem;
});
删除列表项时,takeItem 方法返回指定索引处的列表项指针。正因为这货需要的参数是索引,所以不得不调用 row 方法选获取 current 的索引,再传给 takeItem 方法。列表项被移除后会返回其指针,因为这时候我们不需要它了,所以得 delete 掉其指向的对象。
运行程序后,选中“臭豆腐”。
然后单击右边的“删除”按钮,臭豆腐就没了。
二、QTableWidget
QTableWidget 类派生自 QTableView,也是一个便捷类,可以不创建模型对象而直接添加数据。对应的列表项类型是 QTableWidgetItem。注意,一个 QTableWidgetItem 仅表示一个单元格的数据,所以,如果数据表格有两行两列,那么,你得向里面四个 item。
在添加列表项之前,要先调用:
setRowCount—— 设置表格共有几行;
setColumnCount—— 设置表格共有多少列。
然后设置标题。包括列标题、行标题。一般设置列标题就可以了,行标题通常不用设置(默认显示行号)。
setHorizontalHeaderLabels—— 设置列标题;
setVerticalHeaderLabels—— 设置行标题。
不管是行还是列标题,都可以使用字符串列表(QStringList)来传递,有几行/列就设置几个值。
设置完上述基本参数后,就可以用 setItem 方法来设置每个单元格的数据了。方法原型如下:
void setItem(int row, int column, QTableWidgetItem *item);
row 表示行索引,column 表示列索引,索引从 0 算起。
接下来咱们做个演示:
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
// 创建组件实例
QTableWidget* viewWindow = new QTableWidget;
// 设置标题和大小
viewWindow->setWindowTitle("经典语录");
viewWindow->resize(350, 270);
// 设定行数和列数
viewWindow->setColumnCount(3); // 三列
viewWindow->setRowCount(4); // 四行
// 先弄好列标题
viewWindow->setHorizontalHeaderLabels({"编号", "句子", "伤害指数"});
// 创建列表项
// 注意,每个QTableWidgetItem代表一个单元格
// 第一行
viewWindow->setItem(0, 0, new QTableWidgetItem("001"));
viewWindow->setItem(0, 1, new QTableWidgetItem("你就长这个样子啊?"));
viewWindow->setItem(0, 2, new QTableWidgetItem("2"));
// 第二行
viewWindow->setItem(1, 0, new QTableWidgetItem("002"));
viewWindow->setItem(1, 1, new QTableWidgetItem("你进化到灵长目动物了吗?"));
viewWindow->setItem(1, 2, new QTableWidgetItem("3"));
// 第三行
viewWindow->setItem(2, 0, new QTableWidgetItem("003"));
viewWindow->setItem(2, 1, new QTableWidgetItem("你脑细胞够不够用?"));
viewWindow->setItem(2, 2, new QTableWidgetItem("5"));
// 第四行
viewWindow->setItem(3, 0, new QTableWidgetItem("004"));
viewWindow->setItem(3, 1, new QTableWidgetItem("学姐,你有头吗?"));
viewWindow->setItem(3, 2, new QTableWidgetItem("10"));
// 显示视图窗口
viewWindow->show();
return QApplication::exec();
}
运行结果如下:
三、QTreeWidget
QTreeWidget 类针对的就是树形结构的列表,是 QTreeView 的子类。它对应的列表项是 QTreeWidgetItem 类。
不过这里要注意的是,QTreeWidgetItem 虽然表示树形数据中的一个节点,但它在形式上就像一行数据。因为它可以包含多个列。Qt 的 Tree 视图是可以展示多列的。
下面咱们先做个单列的 Tree 视图。
int main(int argc, char** argv)
{
QApplication app(argc, argv); // 创建视图窗口
QTreeWidget* view = nullptr;
view = new QTreeWidget;
// 先来几个顶层节点
QTreeWidgetItem* item1 = new QTreeWidgetItem({"秦"});
QTreeWidgetItem* item2 = new QTreeWidgetItem({"汉"});
QTreeWidgetItem* item3 = new QTreeWidgetItem({"晋"});
QTreeWidgetItem* item4 = new QTreeWidgetItem({"隋"});
QTreeWidgetItem* item5 = new QTreeWidgetItem({"唐"});
QTreeWidgetItem* item6 = new QTreeWidgetItem({"宋"});
// 给顶层节点添加子节点
// 秦朝
item1->addChild(new QTreeWidgetItem({"胡亥"}));
item1->addChild(new QTreeWidgetItem({"扶苏"}));
item1->addChild(new QTreeWidgetItem({"辛追"}));
item1->addChild(new QTreeWidgetItem({"项籍"}));
// 汉朝
item2->addChildren({
new QTreeWidgetItem({"霍光"}),
new QTreeWidgetItem({"刘向"}),
new QTreeWidgetItem({"司马迁"})
});
// 晋朝
item3->addChildren({
new QTreeWidgetItem({"卫铄"}),
new QTreeWidgetItem({"司马承"}),
new QTreeWidgetItem({"谢安"}),
new QTreeWidgetItem({"王导"})
});
// 隋朝
item4->addChild(new QTreeWidgetItem({"杨坚"}));
item4->addChild(new QTreeWidgetItem({"史万岁"}));
item4->addChild(new QTreeWidgetItem({"王通"}));
// 唐朝
item5->addChildren({
new QTreeWidgetItem({"上官婉儿"}),
new QTreeWidgetItem({"李龟年"}),
new QTreeWidgetItem({"张旭"}),
new QTreeWidgetItem({"杜牧"}),
new QTreeWidgetItem({"武三思"}),
new QTreeWidgetItem({"李靖"})
});
// 宋朝
item6->addChildren({
new QTreeWidgetItem({"王坚"}),
new QTreeWidgetItem({"贾似道"}),
new QTreeWidgetItem({"司马光"}),
new QTreeWidgetItem({"宋慈"}),
new QTreeWidgetItem({"张士逊"})
});
// 将顶层节点添加到QTreeWidget中
view->addTopLevelItems({
item1,
item2,
item3,
item4,
item5,
item6
});
// 隐藏标题栏
view->setHeaderHidden(true);
// 设置窗口标题
view->setWindowTitle("中华名人表");
// 显示窗口
view->show(); return QApplication::exec();
}
QTreeWidgetItem 类的构造函数可以使用字符串列表来初始化显示的文本。原型如下:
explicit QTreeWidgetItem(const QStringList &strings, int type = Type);
在赋值的时候,可以直接用 { },例如
QTreeWidgetItem({"天时", "地利", "人和"});
在上面例子中,因为咱们这次用的只是一列,所以传一个字符串元素就可以了。
QTreeWidgetItem 要添加子节点,可以用这些方法:
// 一次只加一个节点,新节点追加到末尾
void addChild(QTreeWidgetItem *child); // 一次只添加一个节点,但可以指定新节点插入到哪个位置
void insertChild(int index, QTreeWidgetItem *child); // 一次可以添加多个节点,参数是个列表对象
void addChildren(const QList<QTreeWidgetItem*> &children); // 一次可以添加多个节点,能指定插入位置
void insertChildren(int index, const QList<QTreeWidgetItem*> &children);
QTreeWidget 组件用以下方法添加顶层节点:
// 添加一个节点,追加到末尾
void addTopLevelItem(QTreeWidgetItem *item); // 添加一个节点,可以指定插入位置
void insertTopLevelItem(int index, QTreeWidgetItem *item); // 添加多个节点,追加到末尾
void addTopLevelItems(const QList<QTreeWidgetItem*> &items); // 添加多个节点,可指定插入位置
void insertTopLevelItems(int index, const QList<QTreeWidgetItem*> &items);
运行效果如下:
QTreeWidget 类也有 setItemWidget、removeItemWidget 方法。这个就不必多介绍了,和上面 QListWidget 类的一个意思,就是用一个自定义 Widget 显示在数据项上面。
下面咱们做个多列的 Tree 视图。
#include <qapplication.h>
#include <qtreewidget.h> int main(int argc, char* argv[])
{
QApplication app(argc, argv); QTreeWidget * view = new QTreeWidget;
// 设置列数
view->setColumnCount(4);
// 顶层节点
auto itemA = new QTreeWidgetItem({"潜水部"});
auto itemB = new QTreeWidgetItem({"洗脑部"});
auto itemC = new QTreeWidgetItem({"韭菜部"});
// 子节点
itemA->addChildren({
new QTreeWidgetItem({"01", "梁酷裆", "经理", "6"}),
new QTreeWidgetItem({"02", "王晓意", "秘书", "3"})
});
itemB->addChildren({
new QTreeWidgetItem({"03", "于三明", "经理", "4"}),
new QTreeWidgetItem({"04", "周日清", "经理助理", "3"}),
new QTreeWidgetItem({"05", "费洁合", "跟办", "5"})
});
itemC->addChildren({
new QTreeWidgetItem({"06", "安德诗", "经理", "3"}),
new QTreeWidgetItem({"07", "李殿驰", "助理", "2"}),
new QTreeWidgetItem({"08", "易更菁", "文员", "3"})
});
// 添加顶层节点到视图
view->addTopLevelItems({itemA, itemB, itemC});
// 设置列标题
view->setHeaderLabels({"编号", "姓名", "职务", "工龄"});
// 设置窗口标题
view->setWindowTitle("啃瓜装饰服务有限公司员工表");
// 显示窗口
view->show(); return QApplication::exec();
}
效果如下:
代码就不用多解释了吧,单列和多列的节点用法是一样的,只是传递给 QTreeWidgetItem 类构造函数的列表元素个数不同罢了。
【Qt6】列表模型——几个便捷的列表类型的更多相关文章
- Python操作符重载总结&列表模型
操作符重载 二元运算符 特殊方法 + __add__,__radd__ - __sub__,__rsub__ * __mul__,__rmul__ / __div__,__rdiv__,__trued ...
- 复制SharePoint列表项(SPListItem)到另一个列表
从理论上讲,有一个简单到难以置信的解决办法:SPListItem提供了一个CopyTo(destinationUrl)方法(可参考MSDN).不幸的是,这个方法似乎用不了.至少对我的情况(一个带附件的 ...
- 一道Python面试题:给出d = [True, False, True, False, True],请利用列表d,只用一句话返回列表[0,2,4]
看题:给出d = [True, False, True, False, True],请利用列表d,只用一句话返回列表[0,2,4] 这道题的关键是拿到True的索引值,最初我是用list的index方 ...
- 在Bootstrap开发框架中使用bootstrapTable表格插件和jstree树形列表插件时候,对树列表条件和查询条件的处理
在我Boostrap框架中,很多地方需要使用bootstrapTable表格插件和jstree树形列表插件来共同构建一个比较常见的查询界面,bootstrapTable表格插件主要用来实现数据的分页和 ...
- WorldWind源码剖析系列:插件列表视图类PluginListView和插件列表视图项类PluginListItem
WorldWind中的插件类是个庞大的类,可以说从软件设计层面上统筹可扩展的插件体系的设计思想是WorldWind中的精华,值得学习和借鉴.插件体系中的所用到的类可以分为两大类,一类是插件类Plugi ...
- python练习笔记——用列表推导式生成二维列表
用列表推导式如何生成如下列表:[[1, 2, 3], [4, 5, 6], [7, 8, 9]] inner_list = [] outer_list = [] for i in range(1,10 ...
- SharePoint 2013/2010 在一个列表或文档库内移动列表项,文档和目录位置而保持last modify by 等系统字段保持不变
本文讲述SharePoint 2013/2010 在一个列表或文档库内移动列表项.文档和目录位置而保持last modify by 等系统字段保持不变的解决方式. 近期遇到客户一个需求,在一个列表或文 ...
- Flutter实战视频-移动电商-33.列表页_子类和商品列表交互效果
33.列表页_子类和商品列表交互效果 主要实现点击小类下面的列表跟着切换 获取右侧下面的列表信息,即要传递大类的id也要传递小类的,所以需要把左侧的大类的id也要Provide化 可以看下网站上的接口 ...
- Loadrunner查询博客列表并循环删除博客列表中的所有博客
Loadrunner查询博客列表并循环删除博客列表中的所有博客,在博客列表请求中使用关联,获取出列表中博客的数量,并找出博客列表请求的必要参数.关联使用Ordinal=All 找出所有匹配值 查找出所 ...
- Python11之列表2(获取、删除列表元素、列表分片、拷贝)
一.获取列表元素值 列表名 [ 索引值 ] 注:索引值从0开始 nameList = ['詹姆斯','字母哥','乐福','威少','乔治','戴维斯'] nameList[0] '詹姆斯' name ...
随机推荐
- PlayWright(十七)- 参数化
今天来讲下参数化,具体是什么意思呢,举个例子 比如我们要测试登录功能,第一步会填写账号,第二步会填写密码,这是一条完整的操作,但是其中会有很多条用例比如账号错误.密码错误.账号为空.密码为空的各种 ...
- 详解prettier使用以及与主流IDE的配合
很多前端小伙伴在日常使用prettier的时候都或多或少有一点疑惑,prettier在每一个IDE中究竟是怎样工作起来的,为什么配置有时候生效,有时又毫无效果.为了让我们的前端小伙伴更加熟悉这块,本文 ...
- Typescript:基础语法学习(尚硅谷 李立超)
官方文档:https://www.tslang.cn/docs/handbook/typescript-in-5-minutes.html 搭建开发环境 npm i -g typescript安装完成 ...
- F-Beta-Score
F1-Score相关概念 F1分数(F1 Score),是统计学中用来衡量二分类(或多任务二分类)模型精确度的一种指标.它同时兼顾了分类模型的准确率和召回率. F1分数可以看作是模型准确率和召回率的一 ...
- go接收alertmanager告警并发送钉钉
前言 功能:作为 alertmanager 的 webhook receiver,提取需要的数据转发到钉钉群机器人的webhook web框架:gin alertmanager版本:0.24 系统版本 ...
- SpringBoot3集成Redis
目录 一.简介 二.工程搭建 1.工程结构 2.依赖管理 3.Redis配置 三.Redis用法 1.环境搭建 2.数据类型 3.加锁机制 四.Mybatis缓存 1.基础配置 2.自定义实现 五.参 ...
- PE文件结构2(实现PE文件载入)
现在我们已经学完了PE文件格式,但是尚还停留在纸上谈兵的阶段,作为Windows系统上的可执行文件格式,PE文件结构总是和结构体,指针等紧密联系在一起的.理解它的最好方法就是通过写一个类似LordPE ...
- 《Kali渗透基础》03. 被动信息收集
@ 目录 1:被动信息收集 1.1:收集内容 1.2:信息用途 2:域名信息收集 2.1:nslookup 2.1.1:命令参数 2.1.2:示例 - 命令行 2.1.3:示例 - 交互式 2.2:d ...
- 商品详情api接口的应用方向有哪些?
商品详情API接口的应用方向非常广泛,可以应用于以下领域: 电子商务平台:商品详情API接口可以提供商品的基本信息,如名称.描述.价格.图片等,帮助电子商务平台展示和推荐商品.此外,还可以提供商品 ...
- Git命令详细使用指南
Git命令详细使用指南 Git是一种广泛使用的版本控制系统,它可以帮助开发人员跟踪变更.协作项目和有效管理代码仓库.无论你是初学者还是有经验的用户,理解各种Git命令对于高效的代码管理至关重要. 安装 ...