记录下使用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();

自定义delegate

模型的交互和绘制通过自定义delegate来实现,暂时没用到交互,先说下item的绘制。继承了QStyledItemDelegate后,重写paint函数处理item的样式,以及sizeHint函数返回item的大小:

绘制item

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();

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);

模型的数据和展示都处理好后,运行效果如下:

listview展示

过滤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]$")); //根据正则表达式过滤

过滤模型

获取选中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<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);

弄完大概是酱紫的:

最终效果

Demo在这里:->Github链接地址。

qlistview 自定义控件_Qt之QListView使用相关推荐

  1. qlistview 自定义控件_是否可以在QListView中添加自定义窗口小部件?

    I have a large log data (100, 1000, 100000, ... records) and I want to visualize it in the following ...

  2. qt自定义控件_Qt编写自定义控件60-声音波形图

    一.前言 这个控件源自于一个音乐播放器,在写该音乐播放器的时候,需要将音频的数据转换成对应的频谱显示,采用的fmod第三方库来处理(fmod声音系统是为游戏开发者准备的革命性音频引擎,非常强大和牛逼) ...

  3. 第十七章、Model/View开发:QListView的功能及属性

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 一.概述 QListView是从QAbstractItemView 派生的类,实现了QAbstrac ...

  4. winform listview 设置选中项 图片_实战PyQt5: 069-MV框架中的项视图拖放功能

    模型-视图框架完全支持Qt的基本拖放操作,列表.树形和表格部件中的项可以在视图间拖动,数据可以以MIME类型的格式进行导入和导出 Qt提供的标准视图自动支持在视图内部的拖放,其中的项可以被移动以改变显 ...

  5. Qt学习笔记之样式表

    一.概述 Qt的样式表是从Qt4.2开始引入的描述窗口部件外观的机制,类似于HTML的层叠样式表(Cascading Style Sheets,CSS).样式表在Qt的风格之上起作用(如果使用了样式表 ...

  6. Qt 之 模仿 QQ登陆界面——功能篇(一)

    一.简述 今天是2017年第一篇技术文章,12月末事情太多,一直没来得及更新博客.今天继 Qt 之 模仿 QQ登陆界面--样式篇 这一篇 来简单地看一下对登录界面做的一些功能,主要是登录用户下拉列表和 ...

  7. qcombox下拉框样式_ComboBox样式实例及下拉框的定制

    导读 组合框是一个重要且应用广泛的组件,一般由两个子组件组成:文本下拉单部分和按钮部分.在许多既需要用户选择.又需要用户手动输入的应用场景下,组合框能够很好的满足我们的需求.如我们经常使用的聊天软件Q ...

  8. C++Qt开发——Mode View(模型视图)

    Model/View(模型/视图)结构 简介 Model/View(模型/视图)结构是 Qt 中用界面组件显示与编辑数据的一种结构,视图(View)是显示和编辑数据的界面组件,模型(Model)是视图 ...

  9. 样式表(05):【纲】Qt Style Sheets Reference [官翻]

    文章目录 定制样式的小部件列表 属性列表 图标列表 属性类型列表 伪状态列表 子控件列表 Qt Style Sheets Reference Qt样式表支持各种属性.伪状态和子控件,使得定制小部件的外 ...

  10. Qt样式表参考:Qt Style Sheets

    Qt样式表支持各种属性.伪状态和子控件,使得定制小部件的外观成为可能. 可设置样式的小部件列表 下表列出了可以使用样式表自定义的Qt小部件: Widget 如何设计风格 QAbstractScroll ...

最新文章

  1. 如何进行app的兼容性测试?需要考虑哪些方面?
  2. MySQL同步复制搭建方法指南详细步骤
  3. 你必须会的--Dijkstra算法--单源最短路径问题
  4. 【Java报错】借助@PostConstruct解决使用@Component注解的类用@Resource注入Mapper接口为null的问题(原因解析+解决方法)
  5. Ubuntu 启动或停止django服务
  6. 一步步开发自己的博客 .NET版(5、Lucenne.Net 和 必应站内搜索)
  7. LVS负载均衡-NAT模式
  8. Android远程服务与本地服务的特点以及功能差异
  9. 项目案例第二篇中小型公司优化性能安全篇
  10. vue获取编辑器纯文字_前端富文本编辑器 vue-html5-editor
  11. c++ 程序在内存中的分布
  12. Mysql 查看版本号
  13. 24. Declear non-member functions when type conversions should apply to all parameters
  14. session是什么,存储在哪里
  15. 百度测试linux面试题,【百度百度Linux面试题】面试问题:Linux查看… - 看准网
  16. [渝粤题库]西北工业大学离散数学
  17. JavaScript函数——输入某年某月某日,判断这一天是一年中的第几天
  18. 重新编译Spark2.4.0 Parcels包
  19. php6基因突变,基因突变中那些“披着狼皮的羊” 很多“致命性”基因突变正在被证实无害...
  20. 个人日记-《学习究竟是什么》读后感-2020/6/21

热门文章

  1. 计算机与网络期刊多少钱,《计算机与网络》是不是核心期刊
  2. Windows11系统下解压文件后缀为.tar(.gz)的压缩文件
  3. QTableView 常用功能总结
  4. Excel百“练“成钢,从题库随机抽取题目 V 2.0版本
  5. 使用 SOUI 开发高 DPI 桌面应用程序
  6. win10易升_记一次因为升级 Win 10 到 2004 版导致的蓝屏问题的解决
  7. h5支付不能打开支付宝 ios_iOS支付宝H5支付无法返回APP解决方案
  8. maven命令指定配置文件
  9. Git(1)——初始版本控制工具
  10. 判断运行环境是手机还是 PC