文档章节

利用C++11的function和bind功能,实现QStandardItemModel的通用遍历函数

尘中远
 尘中远
发布于 2016/05/12 23:51
字数 1153
阅读 1.3K
收藏 0

精选30+云产品,助力企业轻松上云!>>>

在使用Qt的树形视图和表格视图QTableView和QTreeView时,经常需要遍历所有条目,每种功能都写一个遍历函数既麻烦又不符合编程最简原则,因此,写一个通用的遍历函数是很必要的(类似于std::for_each),对于遍历时实现的功能不一样,可以通过函数指针来代替需要实现的功能。

在讲这个之前,需要了解 std::function和std::bind,具体可以自行谷歌。

由于这个遍历函数可能经常用到,因此可以写一个类的静态函数或者是全局函数。

下面把这个功能封装在一个类里

类的头文件如下:
#include <QStandardItemModel>
#include <functional>
class QStandardItemModelEx
 {
 public:
     QStandardItemModelEx(){}
     ~QStandardItemModelEx(){}
     ///
     /// \brief callback_ergodicFun_ptr 回调函数指针,bool f(QStandardItem*),bool用于决定是否继续,如果为true就继续递归,如果为false就停止递归
     ///
     typedef std::function<bool(QStandardItem*)> callback_ergodicFun_ptr;

     //typedef void(*callback_ergodicFun_ptr)(QStandardItem*);
     static void ergodicAllItem(QStandardItemModel* model,callback_ergodicFun_ptr pFun);
     static bool ergodicItem(QStandardItem* item,callback_ergodicFun_ptr pFun);
 private:
 };

这里使用C++11的新特性function(环境 VS2010),定义一个函数指针用于回调实现功能。
函数 ergodicAllItem用于遍历所有项目, ergodicItem用于遍历项目下的所有子项目。回调函数返回bool用于决定是否继续,如果为true就继续遍历,如果为false就停止遍历
为了简单起见,下面用递归实现遍历( ergodicItem是尾递归函数
 
void QStandardItemModelEx::ergodicAllItem(QStandardItemModel* model,callback_ergodicFun_ptr pFun)
{
    int rows = model->rowCount();
    int column = model->columnCount();
    for (int i=0;i<rows;++i)
    {
        for(int j=0;j<column;++j)
        {
            QStandardItem* item = model->item(i,j);
            if (item)
            {
                if(!ergodicItem(item,pFun))
                    return;
            }
        }
    }
}

bool QStandardItemModelEx::ergodicItem(QStandardItem* item,callback_ergodicFun_ptr pFun)
{
    int rows = item->rowCount();
    int column = item->columnCount();
    for (int i=0;i<rows;++i)
    {
        for(int j=0;j<column;++j)
        {
            QStandardItem* childItem = item->child(i,j);
            if (childItem)
            {
                if(!ergodicItem(childItem,pFun))
                    return false;
            }
        }
    }
    return pFun(item);
}




用这两个函数就可以遍历所有的项目了,而遍历时需要的动作,就通过回调函数实现。

回调函数即可写在类里,也可以写为全局函数,若除了 QStandardItem * 还需要别的参数,那么可以用std::bind帮忙。

下面举一个例子
例子功能是通过关键字高亮条目。在使用QTreeView或QTableView时,在条目多的情况下,需要搜索某些条目,对搜索结果进行高亮,这时,就需要遍历整个View里的条目,对符合的条目进行高亮
遍历的函数已经写好,现在缺少的是回调的函数,由于遍历的函数使用的函数指针是 std : : function ,因此回调函数即可写为全局函数也可以写为类成员函数
回调函数声明:
bool callback_hightLightItem(QStandardItem* item,const QStringList keys);
回调函数实现:
bool callback_hightLightItem(QStandardItem* item,const QStringList keys)
{   
    QString str = item->text();
    if (is_match_string(str,keys))
    {
        item->setData(QVariant(QColor(237,100,100,180)),Qt::BackgroundRole);
    }
    else
    {
        item->setData(QVariant(),Qt::BackgroundRole);
    }
    return true;
}

使用QStandardItem的setData函数,设置角色为Qt::BackgroundRole,即可设置背景颜色。
实现函数中is_match_string函数是用来检测是否符合关键字,如果符合关键字,就返回true,符合关键字就给条目背景赋予不同的颜色,否则就把颜色消除。
回调函数返回true,意味着一直遍历,直到所有遍历完成。

通过按钮pushButton_search来触发搜索功能。 pushButton_search函数的槽如下:
void MainWindow : :on_pushButton_search_clicked()
{
    QString str  = ui - >lineEdit_search - >text(); //获取关键字
     if (str.isEmpty())
         return;
    QStringList keyWords  = str.split(QString( " "));
    StandardItemModel : :ergodicAllItem(
        qobject_cast <QStandardItemModel * >(ui - >treeView - >model())
        ,std : :bind(callback_hightLightItem,std : :placeholders : :_1,keyWords)); //对于callback_hightLightItem是全局函数的情况下
}

由于回调函数是两个参数QStandardItem* item,const QStringList keys,而函数指针只是一个参数,因此需要绑定一个参数,使其变为参数只有一个的函数指针。这时就需要std::bind来实现。
占位符_1表示这个参数是对应的函数指针的第一个参数所在位置,如当前函数是:
bool callback_hightLightItem(QStandardItem* item,const QStringList keys);
我们要把他转换为如下类型的函数指针
bool(QStandardItem*)
第一个参数是正好对应,所以占位符_1就位于第一个位置,后面的参数直接传递进去就行。

如果回调写成:
bool callback_hightLightItem(const QStringList keys,QStandardItem* item);
那么写法变为:
std::bind(callback_hightLightItem,keyWords,std::placeholders::_1);
如果callback_hightLightItem是类成员函数,那么其写法如下
StandardItemModel : :ergodicAllItem(
        qobject_cast <QStandardItemModel * >(ui - >treeView - >model())
        ,std : :bind( &MainWindow : :callback_hightLightItem, this,std : :placeholders : :_1,keyWords));

bind也能轻松搞定类成员函数指针,注意要把类的指针传递过去。
尘中远
粉丝 2
博文 26
码字总数 47436
作品 0
朝阳
程序员
私信 提问
加载中
请先登录后再评论。
Qt树形控件QTreeView使用2——复选框的设置

目录: Qt树形控件QTreeView使用1——节点的操作 Qt树形控件QTreeView使用2——复选框的设置 利用C++11的function和bind功能,实现QStandardItemModel的通用遍历函数 通过QStandardItem和QSt...

尘中远
2016/05/12
1.3K
0
Lambda表达式:代替std::bind的绝佳方法

Lambda表达式:代替std::bind的绝佳方法 lambda表达式使得函数指针有了更灵活的使用方法,但是有些时候,对于大型的函数,还是不建议用lambda表达式,谁也不想在函数里又看到一段长长的函数。...

尘中远
2016/05/12
149
0
C++11之用std::function和std::bind实现观察者模式

使用C++11中的std::bind和std::function以及模板可以很好的实现观察者模式,现在把自己的一些实现的想法记录在此. 编译环境:VS2017 实现的想法:将各个类之间进行解耦,使用C++11的特性实现...

osc_ogi0qclx
2019/08/31
9
0
QStandardItemModel角色控制及QTreeView添加不同的右键菜单

1.概述 QTreeView 最长用的一个功能就是作为导航栏,像vs里的项目结构树,word的文档结构图,资源管理器的文档结构,等等都是利用树形结构组织的,在前面已经讲述了 Qt中使用标准化项目模型Q...

zjxBlog
2014/06/01
168
0
PyQt5系列教程(30): 文本输入栏(QLineEdit)4

这期我们继续介绍一下文本输入栏(QLineEdit),我们已经介绍了其常用属性、信号、函数还有自定义密码输入框,今天是最后一章,文本框自动补全。 若我们想用到QLineEdit自动补全的功能,必须...

学点编程吧
2018/03/02
0
0

没有更多内容

加载失败,请刷新页面

加载更多

java使用jsoup时绕过https证书验证

java 代码 增加一个工具类 在jsoup获取之前调用此方法 //your codeSSLHelper.init();Connection connect = Jsoup.connect(url).userAgent(USER_AGENT);connect.header("Accept","text/htm......

MeiJM
19分钟前
30
0
6 Message 消息提示框

1 element.js导入message import { Message } from 'element-ui'# 赋值给变量,便于this调用Vue.prototype.$message = Message 2 调用 this.$message.error('错误')类型有:success,w......

书阳
19分钟前
16
0
聊聊rocketmq-client-go的strategy

序 本文主要研究一下rocketmq-client-go的strategy AllocateStrategy rocketmq-client-go-v2.0.0/consumer/strategy.go type AllocateStrategy func(string, string, []*primitive.MessageQ......

go4it
47分钟前
21
0
BuildRun低代码开发教程八节 | 图表和仪表盘展示

课程说明 ▍ 1.1 课程实现功能 本课程为物联网应用平台设计一个仪表盘首页,包括以下内容: 卡片展示设备总数; 卡片展示网关总数; 卡片展示产品总数; 卡片展示产品分组总数; 图表展示各运...

BuildRun团队
50分钟前
23
0
JavaSE第03篇:Java基础语法之运算符和流程控制

本章将会延续JavaSE第02篇,详细讲解Java基础语法中的运算符和流程控制中的顺序结构、分支结构。 第一章:运算符 运算符,简而言之就是运算的符号。 我们通常所理解的运算一般和数学有关系,...

雷哒哒
53分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部