QStandardItemModel角色控制及QTreeView添加不同的右键菜单
#define ROLE_MARK_FOLDER Qt::UserRole + 2
#define ROLE_MARK_ITEM Qt::UserRole + 3
这三个role中,ROLE_MARK用于区分 “根节点”,“文件夹节点”,“条目节点”这三种情况。 ROLE_MARK_FOLDER用于区分“cpp文件夹”,“h文件夹”等情况。 ROLE_MARK_ITEM用于区分“条目节点”有可能出现的种类。 当然,对于这种比较少的区分,用一个int型变量进行位的或与操作来判断也是可以的,但这里主要为了演示role的使用方法。 下面在为三种role定义值,定义如下 //对应ROLE_MARK
#define MARK_PROJECT 1 //这是总项目标记
#define MARK_FOLDER 2 //这是文件夹标记
#define MARK_ITEM 3 //条目标记
//对应ROLE_MARK_FOLDER,标记folder种类
#define MARK_FOLDER_H 1 //头文件文件夹标记
#define MARK_FOLDER_CPP 2 //cpp文件文件夹标记
//对应ROLE_MARK_ITEM标记item种类
#define MARK_ITEM_H 1 //头文件条目
#define MARK_ITEM_CPP 2 //cpp文件条目
前期做完,下面开始实现程序 简单界面如下:

加上图标文件

树形视图的初始化: void Widget::init() { QStandardItemModel* model = new QStandardItemModel(ui->treeView); model->setHorizontalHeaderLabels(QStringList()<<QStringLiteral("项目")); //添加项目文件夹 QStandardItem* root = new QStandardItem(QIcon(":/icon/icon/p.png"),QStringLiteral("项目")); root->setData(MARK_PROJECT,ROLE_MARK);//首先它是项目中目录 root->setData(MARK_FOLDER,ROLE_MARK_FOLDER);//其次它属于文件夹 model->appendRow(root); QStandardItem* folder = new QStandardItem(QIcon(":/icon/icon/h-f.png"),QStringLiteral("头文件")); folder->setData(MARK_FOLDER,ROLE_MARK);//首先它是文件夹 folder->setData(MARK_FOLDER_H,ROLE_MARK_FOLDER);//其次它属于头文件文件夹 root->appendRow(folder); folder = new QStandardItem(QIcon(":/icon/icon/c-f.png"),QStringLiteral("源文件")); folder->setData(MARK_FOLDER,ROLE_MARK);//首先它是文件夹 folder->setData(MARK_FOLDER_CPP,ROLE_MARK_FOLDER);//其次它属于源文件文件夹 root->appendRow(folder); ui->treeView->setModel(model); }
在添加条目时,给一些特别的条目设定标志,如头文件文件夹,因为它是文件夹,因此首先给它设定角色为ROLE_MARK的值MARK_FOLDER,其次它在文件夹中属于头文件文件夹,因此再给他设定角色为ROLE_MARK_FOLDER的值MARK_FOLDER_H。这时,这个条目就有两个额外的值用于特殊的判断。 上面代码运行界面如下图所示:

当添加头文件时,需要在头文件文件夹加入条目,按钮“添加h”就是用来模拟添加头文件的过程。 添加头文件时,首先需要找到“头文件”这个文件夹对应的QStandardItem*,实现如函数getHeaderFolder,此函数实现需要先找到“项目”这个顶层文件夹,具体实现如下: QStandardItemModel* Widget::getTreeModel() { return qobject_cast<QStandardItemModel*>(ui->treeView->model()); } QList<QStandardItem*> Widget::getRoots() { QList<QStandardItem*> roots; QStandardItemModel* model = getTreeModel(); for(int i=0;i < model->rowCount();++i) { roots.append(model->item(i)); } return roots; } QStandardItem* Widget::getProjectFolder() { QList<QStandardItem*> roots = getRoots(); for(auto i=roots.begin();i!=roots.end();++i){ if((*i)->data(ROLE_MARK) == MARK_PROJECT){ return (*i); } } return nullptr; } QStandardItem* Widget::getHeaderFolder() { QStandardItem* project = getProjectFolder(); if(nullptr == project) return nullptr; for(int i=0;i < project->rowCount();++i) { QStandardItem* child = project->child(i); QVariant var = child->data(ROLE_MARK_FOLDER); if(!var.isValid()) continue;//说明不是ROLE_MARK_FOLDER,有可能是一些项目,对应项目结构树那个xxx.pro就是一个非文件夹条目 if(MARK_FOLDER_H == var.value<int>()) return child; } return nullptr; } QStandardItem* Widget::getSrcFolder() { QStandardItem* project = getProjectFolder(); if(nullptr == project) return nullptr; for(int i=0;i < project->rowCount();++i) { QStandardItem* child = project->child(i); QVariant var = child->data(ROLE_MARK_FOLDER); if(!var.isValid()) continue;//说明不是ROLE_MARK_FOLDER,有可能是一些项目,对应项目结构树那个xxx.pro就是一个非文件夹条目 if(MARK_FOLDER_CPP == var.value<int>()) return child; } return nullptr; }
getTreeModel用于获取treeView的model; getRoots用于获取所有根节点; getProjectFolder用于获取“项目文件夹”; getHeaderFolder用于获取“头文件文件夹”; getSrcFolder用于获取“源文件文件夹”; 主要使用了data函数,函数声明如下: QVariant QStandardItem::data(int role = Qt::UserRole + 1) const 它会根据role,返回对应的QVariant,如果没有这个role,返回的QVariant会是不可用,可以通过QVariant的函数isValid进行判断。 QVariant函数内部的值需要先转换,转换可以使用toInt函数或者使用一个通用的模板函数value。
下面看看按钮“添加头文件”的实现: void Widget::on_pushButton_clicked() { static int s_header_count = 1; //找到头文件文件夹 QStandardItem* headerFolder = getHeaderFolder(); if(headerFolder) { QStandardItem* item = new QStandardItem(QIcon(":/icon/icon/i.png") ,QStringLiteral("%1.h").arg(s_header_count)); item->setData(MARK_ITEM,ROLE_MARK);//首先标定条目的类型 - 文件夹、项目、条目… item->setData(MARK_ITEM_H,ROLE_MARK_ITEM);//再次标定项目的类型 headerFolder->appendRow(item); ++s_header_count; } }
首先找到对应的头文件文件夹,然后再在这问件夹下添加文件。运行效果如下图:

3.给树形视图设置右键菜单 树形视图最大的优点是有清晰的逻辑关系,可以明显的看出每个条目的父子关系,对于大型工程来说显得尤为重要。由于条目之间功能不同,对条目的操作也会有不同的响应。例如,Qt Creator的项目结构树,对顶层跟项目点右键和对其它节点点右键是弹出不同的菜单的,如下图所示


这里涉及到两个方面,一个是给QTreeView添加菜单,另一个是对右击的节点进行判断。 给QtreeView添加右键菜单,首先需要把contextMenuPolicy属性设置为:CustomContextMenu。

在ui 编辑器中右击QTreeView,选择转到槽

选择customContextMenuRequested(QPointpos)信号

这时,会自动添加对应的槽函数: void Widget::on_treeView_customContextMenuRequested(const QPoint &pos) { }
当然也可以使用代码添加! 此槽函数接收一个点坐标,用于标定点击的方位,可以使用indexAt函数来获取具体点击的条目。 virtual QModelIndex indexAt(const QPoint & point) const 在添加Menu前先要创建menu。声明两个menu的成员变量,记得添加对应的头文件 #include <QMenu>
#include <QAction>
QMenu* m_projectMenu;
QMenu* m_itemMenu; 在构造函数中创建menu m_projectMenu = new QMenu(this); m_itemMenu = new QMenu(this); QAction* ac = nullptr; ac = new QAction(QStringLiteral("构建"),this); m_projectMenu->addAction(ac); ac = new QAction(QStringLiteral("执行qmake"),this); m_projectMenu->addAction(ac); ac = new QAction(QStringLiteral("部署"),this); ac->setEnabled(false); m_projectMenu->addAction(ac); ac = new QAction(QStringLiteral("运行"),this); m_projectMenu->addAction(ac); m_projectMenu->addSeparator(); ac = new QAction(QStringLiteral("重新构建"),this); m_projectMenu->addAction(ac); ac = new QAction(QStringLiteral("清除"),this); m_projectMenu->addAction(ac); m_projectMenu->addSeparator(); ac = new QAction(QStringLiteral("添加新文件……"),this); m_projectMenu->addAction(ac); ac = new QAction(QStringLiteral("余下的省略……"),this); m_projectMenu->addAction(ac); // ac = new QAction(QStringLiteral("打开文件"),this); m_itemMenu->addAction(ac); ac = new QAction(QStringLiteral("在explorer中显示"),this); m_itemMenu->addAction(ac); ac = new QAction(QStringLiteral("在此弹出命令提示"),this); m_itemMenu->addAction(ac); QMenu* itemChildMenu = new QMenu(m_itemMenu); itemChildMenu->setTitle(QStringLiteral("用…打开")); ac = new QAction(QStringLiteral("C++编辑器"),this); itemChildMenu->addAction(ac); ac = new QAction(QStringLiteral("普通文本编辑器"),this); itemChildMenu->addAction(ac); ac = new QAction(QStringLiteral("二进制编辑器"),this); itemChildMenu->addAction(ac); ac = new QAction(QStringLiteral("System Editor"),this); itemChildMenu->addAction(ac); m_itemMenu->addAction(itemChildMenu->menuAction()); ac = new QAction(QStringLiteral("余下省略n条"),this); m_itemMenu->addAction(ac);
on_treeView_customContextMenuRequested槽函数具体实现代码如下: void Widget::on_treeView_customContextMenuRequested(const QPoint &pos) { QModelIndex index = ui->treeView->indexAt(pos); QVariant var = index.data(ROLE_MARK); if(var.isValid()) { if(MARK_PROJECT == var.toInt()) m_projectMenu->exec(QCursor::pos());//弹出右键菜单,菜单位置为光标位置 else if(MARK_ITEM == var.toInt()) m_itemMenu->exec(QCursor::pos()); } }
首先用indexAt获取当前点击条目的QModelIndex。通过QModelIndex获取条目的data,QTreeView的data可以通过model,item,index三者任意一个获取,非常方便。 之前对项目和条目通过ROLE_MARK角色做过标记,只要判断ROLE_MARK角色,就可以区分点击的是根节点项目还是任意一个条目。具体效果见下图


4.系统role的使用 在设定data时,需要制定角色,而自定义角色都是从Qt::UserRole开始往上延伸的,那么Qt::UserRole之前的那些内容是什么呢。Qt为我们定义了一些常用的角色,在Qt::ItemDataRole枚举中。在Qt说明文档中有详细说明(比较懒不想copy,截了一个图)

我们最常用的就是Qt::DisplayRole,也许你用QStandardItemModel从来都不会在代码中用到它,但是,在显示文字过程中,都会调用此role的值。 只要给这些系统role复制,在视图上就会有对应的效果。 如Qt::BackgroundRole用于设置背景色,只要调用setData时把role设置为Qt::BackgroundRole,同时传入的值为一个颜色值,那么它就会在设置背景颜色。 void Widget::on_pushButton_3_clicked() { QModelIndex index = ui->treeView->currentIndex(); if(!index.isValid()) return; getTreeModel()->itemFromIndex(index)->setData(QColor(232,209,57,200),Qt::BackgroundRole); }
效果如下:

Qt::ToolTipRole用于给条目添加额外的说明 在根节点加入一个额外说明如下: void Widget::init() { QStandardItemModel* model = new QStandardItemModel(ui->treeView); model->setHorizontalHeaderLabels(QStringList()<<QStringLiteral("项目")); //添加项目文件夹 QStandardItem* root = new QStandardItem(QIcon(":/icon/icon/p.png"),QStringLiteral("项目")); root->setData(MARK_PROJECT,ROLE_MARK);//首先它是项目中目录 root->setData(MARK_FOLDER,ROLE_MARK_FOLDER);//其次它属于文件夹 root->setData( QStringLiteral("这是关于QStandardItemModel设定角色的教程 详细介绍见:") ,Qt::ToolTipRole ); …… }
效果如图所示:

Qt::TextColorRole用于改变文字颜色,Qt::TextAlignmentRole改变对齐方式,Qt::FontRole控制字体等等,这里不一一介绍。
ps: 高亮背景后需要把高亮取消,就需要遍历所有子节点,并把设置有Qt::BackgroundRole角色的data设置为QVariant();具体遍历见使用了C++11的一些新特性。 void Widget::on_pushButton_4_clicked() { //涉及到遍历,因此使用回调函数,把遍历需要执行的函数传给封装好的遍历 StandardItemModelEx::ergodicAllItem(getTreeModel() ,std::bind(&Widget::callback_clearColor,this,std::placeholders::_1)); } void Widget::callback_clearColor(QStandardItem* item) { item->setData(QVariant(),Qt::BackgroundRole); }
相关热词:
本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!
本文地址: https://www.juheyunku.com/jiaob/qt/9624.shtml
相关文章
热门TAG
命令 外链 企业网站 白帽 php 织梦教程 dedecms修改内容 javascript 织梦 功能 标签 调用 详解 技巧 权重 服务器 网站流量 Dedecms 织梦cms HTML tags标签 python jquery教程 jquery windows 蜘蛛 搜索引擎 网站收录 JSP 实例解析最新文章
-
Qt之QCustomPlot绘图(一)配
时间:2020-12-27
-
QStandardItemModel角色控制及
时间:2020-12-27
-
物联网MQTT协议分析和开源
时间:2020-12-27
-
PyQt5学习笔记14 初识pyqt多
时间:2020-12-26
-
创建一个QtQuickUI项目
时间:2020-12-26
-
Qt3D的研究(九):尝试另
时间:2020-12-26
-
Qt3D的研究(二)
时间:2020-12-26
-
Qt UserInfo
时间:2020-12-26
热门文章
-
Qt UserInfo
时间:2020-12-26
-
PyQt5学习笔记14 初识pyqt多线程操作
时间:2020-12-26
-
PyQt5应用与实践
时间:2020-12-26
-
物联网MQTT协议分析和开源Mosquitto部署验证
时间:2020-12-27
-
Qt3D的研究(九):尝试另外一种边缘检测
时间:2020-12-26
-
创建一个QtQuickUI项目
时间:2020-12-26
-
Qt3D的研究(二)
时间:2020-12-26
-
QStandardItemModel角色控制及QTreeView添加不同
时间:2020-12-27
-
Qt之酒店管理系统
时间:2020-12-26
-
Qt之QCustomPlot绘图(一)配置和第一个例子
时间:2020-12-27
