• 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<SongInfo> listSongInfo;	//歌曲信息的list
    
    	//...省略的步骤
    	//根据关键字strKeyword从网上搜索
    	//并将搜索结果存储到listSongInfo中
    
    	//清除数据模型中之前存在的数据,并重新设置表头(因为clear会把表头也清除掉)
    	clear();
    	setHorizontalHeaderLabels(QStringList() << QString::fromLocal8Bit("音乐标题") << QString::fromLocal8Bit("歌手") << QString::fromLocal8Bit("专辑"));
    	//遍历list,将数据存在表中
    	for (SongInfo songItem : listSongInfo)
    	{
    		QList<QStandardItem *> 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));
    	}
    }
    

    最终的简陋窗口:

    以上只是视图/模型的使用作简单介绍,更多用法还请在实践中自行查找官方文档。

  • 相关阅读:
    Linux硬盘分区方案
    mysql笔记四:索引查询及处理
    thread 学习笔记
    mysql笔记二:基本数据库、表查询操作
    linux 自学系列:监测端口占用情况
    linux 自学系列:命令行传输文件
    mysql笔记三:基本数据库、表创建更新操作
    mysql笔记五:权限管理
    threading源代码问题,为什么要将引入的变量del?
    linux 自学系列:更改系统语言编码
  • 原文地址:https://www.cnblogs.com/hellovenus/p/qt_table_model.html
Copyright © 2020-2023  润新知