Qt之QListView使用
duoziman 2025-05-24 13:27 35 浏览
记录下使用QListView遇到的各种问题
QListView可以用来以列表的形式展示数据,在Qt中使用model/View结构来管理数据与视图的关系,model负责数据的存取,数据的交互通过delegate来实现。
添加数据模型
QT提供了一些现成的models用于处理数据项:
QStringListModel 用于存储简单的QString列表。
QStandardItemModel 管理复杂的树型结构数据项,每项都可以包含任意数据。
QDirModel 提供本地文件系统中的文件与目录信息。
QSqlQueryModel, QSqlTableModel,QSqlRelationTableModel用来访问数据库。
使用Qt自带的模型类QStandardItemModel即可。模型中的每个数据项都有一个与之对应的role来存储某一类数据。需要存取自定义数据可以使用UserRole,UserRole+1...
对于自定义数据类型,如果要使用QVariant,就必须使用Q_DECLARE_METATYPE注册。
struct ItemData{
QString name;
QString tel;
};
Q_DECLARE_METATYPE(ItemData)
单一数据存取
//存
Item->setData(itemStatus,Qt::UserRole); // 单一存取
//取
ItemStatus status = (ItemStatus)(index.data(Qt::UserRole).toInt());
结构体数据存取
//存
Item->setData(QVariant::fromValue(itemData),Qt::UserRole+1);//整体存取
//取
QVariant variant = index.data(Qt::UserRole+1);
ItemData data = variant.value<ItemData>();
自定义delegate
模型的交互和绘制通过自定义delegate来实现,暂时没用到交互,先说下item的绘制。继承了QStyledItemDelegate后,重写paint函数处理item的样式,以及sizeHint函数返回item的大小:
绘制item
【领QT开发教程学习资料,点击下方链接莬费领取↓↓,先码住不迷路~】
点击→领取「链接」
void ItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.isValid())
{
painter->save();
ItemStatus status = (ItemStatus)(index.data(Qt::UserRole).toInt());
QVariant variant = index.data(Qt::UserRole+1);
ItemData data = variant.value<ItemData>();
QStyleOptionViewItem viewOption(option);//用来在视图中画一个item
QRectF rect;
rect.setX(option.rect.x());
rect.setY(option.rect.y());
rect.setWidth( option.rect.width()-1);
rect.setHeight(option.rect.height()-1);
//QPainterPath画圆角矩形
const qreal radius = 7;
QPainterPath path;
path.moveTo(rect.topRight() - QPointF(radius, 0));
path.lineTo(rect.topLeft() + QPointF(radius, 0));
path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius));
path.lineTo(rect.bottomLeft() + QPointF(0, -radius));
path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0));
path.lineTo(rect.bottomRight() - QPointF(radius, 0));
path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius));
path.lineTo(rect.topRight() + QPointF(0, radius));
path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0));
if(option.state.testFlag(QStyle::State_Selected))
{
painter->setPen(QPen(Qt::blue));
painter->setBrush(QColor(229, 241, 255));
painter->drawPath(path);
}
else if(option.state.testFlag(QStyle::State_MouseOver))
{
painter->setPen(QPen(Qt::green));
painter->setBrush(Qt::NoBrush);
painter->drawPath(path);
}
else{
painter->setPen(QPen(Qt::gray));
painter->setBrush(Qt::NoBrush);
painter->drawPath(path);
}
//绘制数据位置
QRect NameRect = QRect(rect.left() +10, rect.top()+10, rect.width()-30, 20);
QRect circle = QRect(NameRect.right(), rect.top()+10, 10, 10);
QRect telRect = QRect(rect.left() +10, rect.bottom()-25, rect.width()-10, 20);
switch (status) {
case S_RED:
painter->setBrush(Qt::red);
painter->setPen(QPen(Qt::red));
break;
case S_BLUE:
painter->setBrush(Qt::blue);
painter->setPen(QPen(Qt::blue));
break;
case S_YELLOW:
painter->setBrush(Qt::yellow);
painter->setPen(QPen(Qt::yellow));
break;
}
painter->drawEllipse(circle); //画圆圈
painter->setPen(QPen(Qt::black));
painter->setFont(QFont("Times", 12, QFont::Bold));
painter->drawText(NameRect,Qt::AlignLeft,data.name); //绘制名字
painter->setPen(QPen(Qt::gray));
painter->setFont(QFont("Times", 10));
painter->drawText(telRect,Qt::AlignLeft,data.tel); //绘制电话
painter->restore();
}
}
QSize ItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return QSize(160, 60);
}
设置item不同状态下的样式
在paint函数中,还可以获得当前item的状态,并设置不同的样式:
if(option.state.testFlag(QStyle::State_Selected)) //选中状态
{
painter->setPen(QPen(Qt::blue));
painter->setBrush(QColor(229, 241, 255));
painter->drawPath(path);
}
else if(option.state.testFlag(QStyle::State_MouseOver))//鼠标划过状态
{
painter->setPen(QPen(Qt::green));
painter->setBrush(Qt::NoBrush);
painter->drawPath(path);
}
else{
painter->setPen(QPen(Qt::gray));
painter->setBrush(Qt::NoBrush);
painter->drawPath(path);
}
设置好模型后,再对QListView进行下属性设置:
ui->listView->setItemDelegate(m_delegate); //为视图设置委托
ui->listView->setSpacing(15); //为视图设置控件间距
ui->listView->setModel(m_model); //为委托设置模型
ui->listView->setViewMode(QListView::IconMode); //设置Item图标显示
ui->listView->setDragEnabled(false);
模型的数据和展示都处理好后,运行效果如下:
过滤item
Qt中提供了一个方便处理模型排序和过滤的类QSortFilterProxyModel,通过他可以非常方便的处理我们的model。将QListView展示的model设置成代理模型:
ui->listView->setItemDelegate(m_delegate); //为视图设置委托
ui->listView->setSpacing(15); //为视图设置控件间距
m_proxyModel = new QSortFilterProxyModel(ui->listView);
m_proxyModel->setSourceModel(m_model);
m_proxyModel->setFilterRole(Qt::UserRole);
m_proxyModel->setDynamicSortFilter(true);
ui->listView->setModel(m_proxyModel); //为委托设置模型
ui->listView->setViewMode(QListView::IconMode); //设置Item图标显示
ui->listView->setDragEnabled(false); //控件不允许拖动
其中,m_proxyModel->setFilterRole(Qt::UserRole);设置根据模型的某一项数据来处理模型的过滤。proxyModel可以设置过滤的方式,根据QString或者正则表达式来过滤:
m_proxyModel->setFilterFixedString(QString::number(S_RED));//根据字符串过滤
m_proxyModel->setFilterRegExp(QRegExp("^[0|2]#34;)); //根据正则表达式过滤
获取选中item
对于列表中item的操作,可以是在delegate中处理交互事件,也可以通过QListView获取到所有选中item的QModelIndex,然后对模型本身进行修改。这里我选择的后者:
QModelIndexList modelIndexList = ui->listView->selectionModel()->selectedIndexes();
设置多选
将QListView的selectionBehavior设置成MultiSelection即可。
对于多选的时候,模型的修改有一个坑。在设置了代理模型后,由于开启了动态排序模式,如果修改代理模型的数据,在第一个item修改数据后可能就不在当前过滤模型中,会被过滤掉,后面的item的QModelIndex就会变化,导致后续的修改失败。
dynamicSortFilter : bool
This property holds whether the proxy model is dynamically sorted and filtered whenever the contents of the source model change.
Note that you should not update the source model through the proxy model when dynamicSortFilter is true. For instance, if you set the proxy model on a QComboBox, then using functions that update the model, e.g., addItem(), will not work as expected. An alternative is to set dynamicSortFilter to false and call sort() after adding items to the QComboBox.
The default value is true.
有两个方法处理这个坑,一是不修改代理模型,修改源模型的数据。二是在修改模型数据的时候关闭代理模型的动态排序功能。
修改数据
QModelIndexList sourceIndexList;
foreach (QModelIndex modelIndex, modelIndexList){
sourceIndexList<<m_proxyModel->mapToSource(modelIndex); //获取源model的modelIndex
}
// g_proxyModel->setDynamicSortFilter(false);
foreach (QModelIndex sourceIndex, sourceIndexList){
ItemStatus status = (ItemStatus)(sourceIndex.data(Qt::UserRole).toInt());
qDebug() << "Index : " << sourceIndex.row();
switch (status) {
case S_RED:
redNum--;
break;
case S_BLUE:
blueNum--;
break;
case S_YELLOW:
yellowNum--;
break;
}
status = S_RED;
redNum++;
m_model->setData(sourceIndex,status,Qt::UserRole);
}
// g_proxyModel->setDynamicSortFilter(true);
弄完大概是酱紫的:
相关推荐
- 盘点足球游戏FC24中每个英超俱乐部评分最高的球员
-
著名足球游戏《FC24》的球员数据库已经陆续公布,来自世界各地的球迷已经能够查看游戏中的每位英超球员的评分。在英超联赛,一些俱乐部的球员获得了很高的评分,而其他俱乐部,尤其是升班马卢顿,今年则是一套...
- 出去打野了!官宣:多特蒙德 超级小妖离队!
-
穆科科2016年夏天,加盟多特蒙德。2020年,穆科科完成德甲首秀,成为德甲历史上最年轻的球员。2022年11月,穆科科入选德国国家男子足球队出征2022年卡塔尔世界杯的26人大名单,并完成德国国家...
- 巅峰对决!巴黎与拜仁分别排名FootballDatabase世界第一、第二
-
北京时间7月6日0点,巴黎圣日耳曼将在世俱杯1/4决赛中迎战拜仁慕尼黑。根据足球数据网站FootballDatabase的数据,巴黎圣日耳曼与拜仁慕尼黑分别是现世界第一、第二。巴黎圣日耳曼本赛季夺得...
- 镜报:评选二十大杰出少帅
-
谁是世界足坛最佳少帅?英国媒体《镜报》的《足球经理》板块为了找出答案进行了大规模的数据搜索。有超过13000名工作人员为足球经理数据库的采取工作做出贡献,他们同样也搜集世界各地球员的数据。本次评选出的...
- 5大维度拆解向量数据库:从768维向量到HNSW索引的底层逻辑
-
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在官网-聚客AI学院大模型应用开发微调项目实践课程学习平台一、向量数据库:AI时代的"记忆中枢"1.1核心概...
- Oracle 数据库、表、方案的逻辑备份与恢复
-
数据库(表)的逻辑备份与恢复逻辑备份是指使用工具export将数据对象的结构和数据导出到文件的过程,逻辑恢复是指当数据库对象被破坏而使用工具import利用备份的文件把数据对象导入到数据库的过程,逻辑...
- 从 PostgreSQL 到 DolphinDB:数据实时同步一站式解决方案
-
随着越来越多的用户使用DolphinDB,各种不同的应用的场景也对DolphinDB的数据接入提出了不同的要求。部分用户需要将PostgreSQL的数据实时同步到DolphinDB中来,...
- Linux不重启识别新挂载磁盘(linux不重启识别新挂载磁盘怎么办)
-
一、概述RAC数据库扩容存储空间,新挂载过来的盘没有识别到,通过fdisk-l命令没有看到。经查询需要重启或者扫描来看到新挂载的磁盘,今天分享一下具体的方法环境:OEL6.4和RAC11.2...
- ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务
-
早上同事用PL/SQL连接虚拟机中的Oracle数据库,发现又报了“ORA-12514TNS监听程序当前无法识别连接描述符中请求服务”错误,帮其解决后,发现很多人遇到过这样的问题,因此写着这里。也...
- ORACLE体系 - 2(oracle体系结构思维导图)
-
【二】实例管理及数据库的启动/关闭2.1参数文件2.1.1概念1)instance在启动阶段读取初始化参数文件(initparameterfiles),该文件管理实例相关启动参数。基本初始化参数...
- 快速解决Win远程桌面CredSSP加密数据库修正问题!
-
前不久我做渗透测试时,在Win10下通过Mstsc访问服务器的3389端口时,遇到了“身份验证错误,要求的函数不受支持”这个错误。这通常是由于客户端和服务器的CredSSP加密协议不匹配导致的。(一...
- Win10出现Windows已阻止安装未具有数字签名的驱动程序的解决方法
-
我们在使用Win10系统的过程中,可能会遇到许多问题。近期有不少网友反馈,在Win10系统中安装某设备的驱动程序时,出现了“Windows已阻止安装未具有数字签名的驱动程序”的提示。那么这个问题应该如...
- Data Guard高级玩法-闪回恢复failover备库
-
今天看到有一个网友提了一个问题,描述很简短测试DG时,主库不能宕机,如何测试failover?其实这个需求从业务层面来说是合理的,一个数据量很大的核心数据库,如果需要做灾难演练,就希望在备库上做...
- Oracle报错ora-12514检查及解决方法
-
1.查看Oracle当前监听器状态在命令行窗口输入lsnrctlstatus命令,查看Oracle当前监听器的状态其中,监听程序参数文件listener.ora配置了要监听的Oracle服务的信息...
- OGG同步到Kafka(ogg kafka flink)
-
目的:测试使用OGG将数据单向同步到Kafka上。简要说明:Kafka使用单节点单Broker部署;单独部署简单ZooKeeper;需要使用到JAVA1.8;OGG需要2个版本,一个fororacl...
- 一周热门
-
-
Python异步 操作MySQL 连接池,打破数据库瓶颈!提升性能
-
什么是 CDN 缓存命中率以及如何计算和优化它?
-
Greenplum: 基于PostgreSQL的分布式数据库内核揭秘
-
【GP最佳实践-04】性能PK!Greenplum VS Oracle,谁更强?
-
TiDB、OceanBase都在谈的HTAP,为何如此燚?
-
武汉达梦数据库申请全密态数据库的密钥更新方法专利,保障密钥存储设备安全
-
MySQL数据库重命名方法汇总(mysql重命名列名)
-
「技成周报2期」西门子各系列常见问题解答
-
ChatGPT盛行的当下,向量数据库为大模型配备了一个超级大脑
-
益生菌的前世今生,细数益生菌的十大好处,可对抗十大疾病
-
- 最近发表
- 标签列表
-
- cache数据库 (32)
- access数据库入门教程 (32)
- 查看数据库版本 (37)
- sqlserver数据库备份 (37)
- java连接mysql数据库 (34)
- 数据库死锁 (33)
- 数据库系统的核心是 (32)
- 数据库管理系统有哪些 (32)
- 数据库用户 (33)
- oracle数据库安装 (33)
- 数据库优化 (32)
- 数据库表设计 (32)
- olap数据库 (34)
- ieee数据库 (34)
- 数据库语言 (33)
- python数据库 (32)
- 本地数据库 (33)
- 数据库加密 (34)
- 数据库集群 (37)
- 数据库隔离级别 (33)
- 数据库设计文档 (35)
- 达梦数据库价格 (32)
- 非关系型数据库有哪些 (33)
- 华东师大公共数据库 (34)
- phpmyadmin连接数据库 (33)