Qt开发用于表格QTableView的模型
如果想使用表格来呈现数据,Qt提供了一个方便的部件QTableWidget,但是直接用它实现一些功能可能比较困难。这里将介绍一种强大、灵活的方式来操作表格。 一、模型/视图架构
在这个架构中, 模型 用于存储数据, 视图 用于呈现数据,除此之外,还有一个称为 委托 的部分,委托显示视图中的每一项,并为可编辑的项提供合适的编辑器。
三者的关系如下图所示——
这篇博客只介绍模型/视图的部分,接下来用一个简单的例子来说明如何使用。 二、要实现的功能
以网易云音乐为例,它的部分搜索界面是这样的:
现在,我们依照网易云音乐做一个下面的窗口,并实现额外的一些功能。
要实现的功能:
1. 网上搜索 :从网上搜索歌曲的数据并呈现在左边的表格中;
2. 本地搜索并选中 :在左边的表格中进行搜索, 选中 与关键字相匹配的行;
3. 本地搜索并过滤 :在左边的表格中进行搜索,只显示与关键字相匹配的行,过滤隐藏不匹配的行。 三、联网搜索1.准备工作
左边的表格使用 QTableView 。
为了存储数据,需要使用合适的模型,在这里我们使用 QStandardItemModel 。
同时为了实现过滤,需要另一个代理模型 QSortFilterProxyModel 。//数据模型 class MusicInfoModel : public QStandardItemModel { public: void loadData(const QString &strKeyword);//用于加载网上搜索得到的数据 } //主窗口 class MainWidget : public QWidget { private slots: void searchOnlineSlot(); //网上搜索 void searchAndSelcLocalSlot(); //本地搜索并选择 void searchAndFilterLocalSlot(); //本地搜索并过滤 private: MusicInfoModel *m_pInfoModel; //数据模型 QSortFilterProxyModel *m_pFilterModel; //过滤代理模型 }
以上只列出重要的成员变量和成员函数。
为了方便加载数据,我们将QStandardItemModel 子类化 ,在子类中声明一个加载数据的函数 loadData 。
在主窗口的构造函数中初始化视图和模型—— m_pInfoModel = new MusicInfoModel(this); m_pFilterModel = new QSortFilterProxyModel(this); m_pFilterModel->setSourceModel(m_pInfoModel); ui.musicInfoTblView->setModel(m_pFilterModel);
从上面可以看到,表格的视图模型是代理模型filterModel,而不是实际包含数据的模型infoModel。 2.加载数据
接下来网上搜索,获得数据并加载到表格中
首先定义歌曲信息的数据结构 //歌曲信息的数据结构 struct SongInfo { public: QString strName; //歌曲标题 QString strSinger; //歌手名字 QString strAlbum; //专辑名称 };
完成数据模型中加载数据的函数: void MusicInfoModel::loadData(const QString &strKeyword) { QList listSongInfo; //歌曲信息的list //...省略的步骤 //根据关键字strKeyword从网上搜索 //并将搜索结果存储到listSongInfo中 //清除数据模型中之前存在的数据,并重新设置表头(因为clear会把表头也清除掉) clear(); setHorizontalHeaderLabels(QStringList() << QString::fromLocal8Bit("音乐标题") << QString::fromLocal8Bit("歌手") << QString::fromLocal8Bit("专辑")); //遍历list,将数据存在表中 for (SongInfo songItem : listSongInfo) { QList listItems; QStandardItem *pTitle = new QStandardItem(songItem.strName); QStandardItem *pSinger = new QStandardItem(songItem.strSinger); QStandardItem *pAlbum = new QStandardItem(songItem.strAlbum); listItems << pTitle << pSinger << pAlbum; appendRow(listItems);//加载一行数据 } } 注意:表中的每一项是一个QStandardItem,在加载一行之前,需要先把他们存储在一个QList中,然后调用appendRow函数,一次完成加载3列。
接下来,我们在主界面中调用数据模型对象的loadData函数,即可将数据全部填到表格中。 四、本地搜索并过滤
过滤很简单,只需要使用 QSortFilterProxyModel 中的相关函数。 void MainWidget::searchAndFilterLocalSlot() { QString strKeyword = ui.textEdit->text(); m_pFilterModel->setFilterFixedString(strKeyword);//根据字符串过滤 }
一些有用的函数:
void setFilterKeyColumn(int column) :设置根据表的哪一列进行过滤,默认值为0,如果设置成-1,则会根据所有列进行搜索。
setFilterFixedString(const QString &) :根据固定的字符串进行过滤。
setFilterRegExp(const QRegExp &) :根据正则表达式进行过滤。五、本地搜索并选中void MainWidget::searchAndSelcLocalSlot() { QItemSelection selection; int iFirstSelcRow = -1; for (int i = 0; i < m_pFilterModel->rowCount(); ++i) { //获得每一行的歌名、歌手名、专辑名 QModelIndex songIndex = m_pFilterModel->index(i, 0); QModelIndex singerIndex = m_pFilterModel->index(i, 1); QModelIndex albumnIndex = m_pFilterModel->index(i, 2); QString strSong = m_pFilterModel->data(songIndex).toString(); QString strSinger = m_pFilterModel->data(singerIndex).toString(); QString strAlbumn = m_pFilterModel->data(albumnIndex).toString(); //判断是否符合条件 if (strSong.contains(strKeyword) || strSinger.contains(strKeyword) || strAlbumn.contains(strKeyword)) { if (iFirstSelcRow == -1) { iFirstSelcRow = i; } //增加选中项 QItemSelection rowSelc(songIndex, songIndex); selection.merge(rowSelc, QItemSelectionModel::Select); } } //清除之前所有选中项,并选中现在的所有匹配项 QItemSelectionModel *pSelcModel = ui.musicInfoTblView->selectionModel(); pSelcModel->clearSelection(); pSelcModel->select(selection, QItemSelectionModel::Rows | QItemSelectionModel::Select); //视图滚动到第一个选中项的位置 if (iFirstSelcRow != -1) { ui.musicInfoTblView->scrollTo(m_pFilterModel->index(iFirstSelcRow, 0)); } }
最终的简陋窗口:
以上只是视图/模型的使用作简单介绍,更多用法还请在实践中自行查找官方文档。
点击领取Qt学习资料+视频教程~「链接」
最不健康的油是什么油?是大豆油吗?提醒这4种油或要少吃民以食为天,随着生活水平的不断提高,人们对美食的研究也下了很多功夫,美食种类越来越多,令人垂涎欲滴。在每一道佳肴的背后,都不能缺少食用油,食用油是厨房内的必备品,也是人体所需的一种
邂逅自己邂逅,很奇妙的两个字,唇齿之间婉绕,便有一份天然的旖旎,足以动人心旌!邂逅不是等候,因为不是刻意为之,所以,常常会有意料之外的惊喜!但这一份惊喜,可遇,不可求!人这一生,与无数的情
透析童年之回到刚出生的时候有一首歌是这样唱的爱我你就抱抱我,爱我你就亲亲我亲爱的早已为人父母的我们,你有多久没有抱过那已慢慢长大的孩子了?你有多久没有亲过深爱自己的爸爸妈妈了?只有孩子在表达情感的时候,才会
一辈子,两件事作者明心君来源一心问禅(IDyxwc1927)做人干干净净,做事踏踏实实。01hr人这一生,就像是一场漫长的旅行。一路上,伴随着各种坎坷挫折,艰难险阻,谁都走得不容易。纵然世间千变
大蒜能杀菌抗肿瘤?每周生吃两次可降低44肺癌风险?靠谱吗生吃大蒜能抗癌!吴伯最近迷上了生吃大蒜,一开口就熏得别人马上逃走。这不,今天他又开始拿着一瓣蒜开始就着酒来吃,不过因为之前买得太多,蒜都放发芽了,他也丝毫不介意。你这一天天的,总吃
鸡脖鸡尖翅鸡皮不能吃?真相来了鸡肉深受大多数人的喜爱但网上关于鸡肉的说法也是各式各样有人说鸡头当中含有重金属物质,食用有危害有人说鸡皮不能吃,不然会中毒甚至还有人说鸡屁股不能吃,否则会致癌那么这些说法到底是真是
肛门瘙痒的饮食肛门瘙痒症是指肛门周围皮肤无任何原发皮肤损害而仅有瘙痒症状的一种皮肤病,该类症状属于临床上常见的症状之一,引起这类疾病的因素也比较多,常见的主要有食用辛辣刺激性比较强的食物以及调料
2022年现实世界的19个物联网应用在过去五年左右的时间里,物联网这个词变得越来越流行,看起来我们会在未来几年听到更多关于它的消息。但是,就像其他像这样的热门流行语一样,许多人挠头问这是什么,我为什么要关心?这就是我
雷霆杯震撼来袭!揭幕战阵容豪华无比,新玩法或对选手造成影响?伴随着就近日王者荣耀KPL夏季赛的完美收官,虽然武汉ES战队再次力排众议强势夺冠成为最后赢家,但是对于大部分喜欢观看比赛的网友而言却依然感到意犹未尽。为此虎牙直播平台以此为契机开启
LPL夏决首发名单出炉!TES临场换将,上单晴天披挂上阵对战369LPL夏季赛决赛如期打响,TES和JDG这两支战队经历了季后赛的各种历练后,终于要站在LPL夏决的舞台上再次碰面交手。不论这场决赛会是谁赢下比赛拿到冠军,TESJDG都将翻开LPL
我带妈妈玩动森妈妈们的可爱行为大赏本文来自游研社APP社区用户投稿,如果你对自己的游戏经历或是有趣见闻有撰写成文章的想法,也可以前往游研社APP投稿中心与我们分享。不久前,我无意间在小红书上刷到了一个帖子,帖子的内