键鼠自动化2.0树形结构讲解

2023-11-21 15:30

本文主要是介绍键鼠自动化2.0树形结构讲解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

介绍

在键鼠自动化2.0中使用Qtc++实现了全自定义树形结构,实现任务的拖拽,复制粘贴,撤销重做,以及包括树形结构增加序号展示,以及增加搜索功能

实现

1.自定义节点

// 自定义节点类
class TreeNode : public QObject {
public:TreeNode(QObject *parent = nullptr): QObject(parent) {}
public:bool isInChild = false; //是否接受子节点QString nodeText; //用于判断的节点名称QString nodeItemTest; //显示的名称QVariant taskData; //数据存储QList<TreeNode*> children; //子节点TreeNode* parent = nullptr; //父节点MyStandardItem* item; //itemint number = -1; //临时使用// 重载==运算符以判断nodeText是否相等bool operator==(const TreeNode& other) const {return nodeText == other.nodeText;}
};

2.拖拽功能

重写拖拽相关函数

   void startDrag(Qt::DropActions supportedActions);void dragLeaveEvent(QDragLeaveEvent* event);void dragEnterEvent(QDragEnterEvent *event);void dragMoveEvent(QDragMoveEvent *event);void dropEvent(QDropEvent *event);void paintEvent(QPaintEvent* event);

部分核心代码

if (sourceNode->parent == nullptr && targetNode->parent == nullptr) { //父与父//当前是父节点与父节点直接拖拽int sourceRow = sourceNode->item->row();qDebug() << MyDebug << "1111111111111111" << targetRow << sourceRow;if (targetRow != sourceRow) {//在目标源下插入一行if (sourceNode->children.isEmpty()) {TreeNode* node;if (isAppendParent) {node = this->appendChileItem(targetNode, sourceNode);}else {node = this->insertTopItem(sourceNode, targetRow);}cmdAdd->appNodeList(node);this->selectionModel()->select(node->item->index(), QItemSelectionModel::SelectCurrent);//删除来源itemthis->removeTopItem(sourceNode);}else if (!sourceNode->children.isEmpty()) {//如果来源里面有子节点就需要递归插入,先查入头节点TreeNode* newParentNode;if (isAppendParent) {newParentNode = this->appendChileItem(targetNode, sourceNode);}else {newParentNode = this->insertTopItem(sourceNode, targetRow);}this->selectionModel()->select(newParentNode->item->index(), QItemSelectionModel::SelectCurrent);//递归插入for (int i = 0 ; i < sourceNode->children.size(); ++i) {this->RecursionInsert(newParentNode, sourceNode->children.at(i));}cmdAdd->appNodeList(newParentNode);//删除来源itemthis->removeTopItem(sourceNode);}else {qDebug() << MyDebug << "未知动作!!!!!!!!!!!!!!!!!!!!!!!!";}}}

3.复制粘贴

void MyTreeView::copyItemRow()
{QModelIndexList selectedIndexes = this->selectedIndexes();if (selectedIndexes.size() <= 0) return;// 使用自定义的比较函数进行排序(从大到小)std::sort(selectedIndexes.begin(), selectedIndexes.end(), compareModelIndex);m_CopyListData.clear();for (int i = 0; i < selectedIndexes.size(); ++i) {MyStandardItem* sourceItem = dynamic_cast<MyStandardItem*>(model->itemFromIndex(selectedIndexes.at(i)));TreeNode* sourceNode = findNodeByText(sourceItem->m_NodeText, m_TreeListData);TreeNode* nodeData = new TreeNode;nodeData->isInChild = sourceNode->isInChild;nodeData->nodeText = sourceNode->nodeText;nodeData->nodeItemTest = sourceNode->nodeItemTest;nodeData->parent = sourceNode->parent;nodeData->taskData = sourceNode->taskData;if (!sourceNode->children.isEmpty()) {QList<TreeNode*> childNodeList;RecursionCopyData(sourceNode, childNodeList);nodeData->children = childNodeList;}m_CopyListData << nodeData;}
}void MyTreeView::pasteItemRow()
{QModelIndexList selectedIndexes = this->selectedIndexes();MyStandardItem* targetItem;if (selectedIndexes.size() <= 0) {targetItem = dynamic_cast<MyStandardItem*>(model->item(model->rowCount() - 1));}else {std::sort(selectedIndexes.begin(), selectedIndexes.end(), compareModelIndex);targetItem = dynamic_cast<MyStandardItem*>(model->itemFromIndex(selectedIndexes.first()));}if (!targetItem) return;TreeNode* targetNode = findNodeByText(targetItem->m_NodeText, m_TreeListData);QList<TreeNode*> undoNodeList;for (int i = 0; i < m_CopyListData.size(); ++i) {TreeNode* node = m_CopyListData.at(i);//判断目标行是父节点还是子节点if (targetNode->parent == nullptr) {TreeNode* newParentNode = insertTopItem(node, targetItem->row() + 1);//如果存在子节点递归插入if (!node->children.isEmpty()) {for (int number = 0 ; number < node->children.size(); ++number) {RecursionInsert(newParentNode, node->children.at(number), false);}}undoNodeList << newParentNode;}else {// qDebug() << MyDebug << "222222222222222" << targetNode->nodeItemTest << targetItem->row() << node->nodeItemTest;TreeNode* nodeTemp = insertChileItem(targetNode->parent, node, targetItem->row() + 1);if (!node->children.isEmpty()) {for (int number = 0 ; number < node->children.size(); ++number) {RecursionInsert(nodeTemp, node->children.at(number), false);}}undoNodeList << nodeTemp;}}AddRowCommand* cmd = new AddRowCommand(this, undoNodeList);m_Undo.append(cmd);m_Redo.clear();emit signalUpdateTableView();
}

4.撤销重做

实现基类command,虚函数撤销与重做,依次实现add和del以及多行拖拽类存储。

class Command {
public:virtual ~Command() = default;virtual void undo() = 0;virtual void redo() = 0;
};class AddRowCommand : public Command
{
public:AddRowCommand(MyTreeView* view, QList<TreeNode*> nodeList = QList<TreeNode*>());void appNodeList(TreeNode* nodeData);void undo();void redo();
private:MyTreeView* m_View;QList<int> m_RowList;QList<bool> m_IsParentList;QList<QString> m_ParentNodeText;QList<TreeNode*> m_NodeList;
};//该类注意事项
//1.要注意先增加类对象再删除node,否则删除后再增加找不到子节点和自身对象等等问题
class DelRowCommand : public Command
{
public:DelRowCommand(MyTreeView* view, QList<TreeNode*> nodeList = QList<TreeNode*>());void appNodeList(TreeNode* nodeData);void undo();void redo();
private:MyTreeView* m_View;QList<int> m_RowList; //item的行存储,因为item会丢失所以保存行QList<bool> m_IsParentList; //保存item是否是父节点QList<QString> m_ParentNodeText; //父节点nodetext保存QList<TreeNode*> m_NodeList;
};class DragRowCommand : public Command
{
public:DragRowCommand(MyTreeView* view, QList<Command*> cmdList, bool bigToSmall);void undo();void redo();
private:MyTreeView* m_View;QList<Command*> m_CmdList;bool m_BigToSmall;
};

5.行号

如何实现QTreeView的行号功能?
这里采用了QTabelView功能,布局中放下了tableview和treeview,行号在treeview的左侧,当滚动或者新增数据,来更新一下视图数据,当展开或者合并节点,同步更新数据,来实现所有节点的独立行号。

public slots://读取滚动条数据同步void onReadScrollValue(int value);//遍历节点子节点下的所有数量int CountTotalChildren(TreeNode* node);//递归更新子节点数据void RecursionUpdateChild(TreeNode* node);//展开void onEntered(const QModelIndex &index);//合并void onCollapsed(const QModelIndex &index);//获取是删除还是delvoid onReadIsAddAndDel(int isAdd, bool isHide);//更新视图数据void onUpdateView();
protected:void wheelEvent(QWheelEvent* event);void mousePressEvent(QMouseEvent *event);void mouseReleaseEvent(QMouseEvent *event);void mouseDoubleClickEvent(QMouseEvent *event);

6. QTreeview的搜索功能

核心代码节点递归搜索,递归搜索节点返回所有包含的数据,通过存到列表中,加一个当前index来实现上下的切换,

QList<TreeNode*> MyTreeView::findNodeItemText(const QString &findStr)
{QList<TreeNode*> TreeNodeList;for (int i = 0; i < m_TreeListData.size(); ++i) {TreeNode* node = m_TreeListData.at(i);recursiveFindNodeByTextItem(findStr, node, TreeNodeList);}return TreeNodeList; // 未找到匹配的节点
}void MyTreeView::recursiveFindNodeByTextItem(const QString &targetText, TreeNode *currentNode, QList<TreeNode *> &list)
{QString nodeStr = currentNode->nodeItemTest;nodeStr.remove(Tools::getInstance()->m_HtmlTitleBegin);nodeStr.remove(Tools::getInstance()->m_HtmlTitleEnd);nodeStr.remove(Tools::getInstance()->m_HtmlTextBegin);nodeStr.remove(Tools::getInstance()->m_HtmlTextEnd);nodeStr.remove(Tools::getInstance()->m_HtmlHiglightBegin);nodeStr.remove(Tools::getInstance()->m_HtmlHiglightEnd);if (nodeStr.contains(targetText)) {list.append(currentNode);}for (TreeNode* child : currentNode->children) {recursiveFindNodeByTextItem(targetText, child, list);}
}

7.其他功能

1.关于如何实现的treeview的富文本
重新绘制的富文本,当然会比正常文本的资源消耗更高,速度较慢,实际测试几十万行并不会卡,但是比较慢一点,日常能接受。

//自定义代理类用来绘制文字富文本
class RichTextDelegate : public QStyledItemDelegate
{
public:RichTextDelegate(QObject* parent = nullptr): QStyledItemDelegate(parent){}void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override;
};
void RichTextDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{QString text = index.data(Qt::DisplayRole).toString();QStyleOptionViewItem opt = option;initStyleOption(&opt, index);painter->save();// 手动绘制背景,用于选中和进入的样式if (opt.state & QStyle::State_Selected) {// 选中状态下的背景颜色为204, 232, 255QBrush backgroundBrush(QColor(185, 232, 255));painter->fillRect(opt.rect, backgroundBrush);}else if (opt.state & QStyle::State_MouseOver) {// 进入状态下的背景颜色为225, 243, 255QBrush backgroundBrush(QColor(235, 243, 255));painter->fillRect(opt.rect, backgroundBrush);}// 手动绘制文本QTextDocument doc;doc.setHtml(text);opt.text = "";painter->translate(option.rect.topLeft());doc.drawContents(painter);painter->restore();
}

这篇关于键鼠自动化2.0树形结构讲解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/403240

相关文章

hdu1011(背包树形DP)

没有完全理解这题, m个人,攻打一个map,map的入口是1,在攻打某个结点之前要先攻打其他一个结点 dp[i][j]表示m个人攻打以第i个结点为根节点的子树得到的最优解 状态转移dp[i][ j ] = max(dp[i][j], dp[i][k]+dp[t][j-k]),其中t是i结点的子节点 代码如下: #include<iostream>#include<algorithm

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

计算机毕业设计 大学志愿填报系统 Java+SpringBoot+Vue 前后端分离 文档报告 代码讲解 安装调试

🍊作者:计算机编程-吉哥 🍊简介:专业从事JavaWeb程序开发,微信小程序开发,定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事,生活就是快乐的。 🍊心愿:点赞 👍 收藏 ⭐评论 📝 🍅 文末获取源码联系 👇🏻 精彩专栏推荐订阅 👇🏻 不然下次找不到哟~Java毕业设计项目~热门选题推荐《1000套》 目录 1.技术选型 2.开发工具 3.功能

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

自定义类型:结构体(续)

目录 一. 结构体的内存对齐 1.1 为什么存在内存对齐? 1.2 修改默认对齐数 二. 结构体传参 三. 结构体实现位段 一. 结构体的内存对齐 在前面的文章里我们已经讲过一部分的内存对齐的知识,并举出了两个例子,我们再举出两个例子继续说明: struct S3{double a;int b;char c;};int mian(){printf("%zd\n",s

如何使用Ansible实现CI/CD流水线的自动化

如何使用Ansible实现CI/CD流水线的自动化 持续集成(CI)和持续交付(CD)是现代软件开发过程中的核心实践,它们帮助团队更快地交付高质量的软件。Ansible,作为一个强大的自动化工具,可以在CI/CD流水线中发挥关键作用。本文将详细介绍如何使用Ansible实现CI/CD流水线的自动化,包括设计流水线的结构、配置管理、自动化测试、部署、以及集成Ansible与CI/CD工具(如Jen

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据

C语言程序设计(选择结构程序设计)

一、关系运算符和关系表达式 1.1关系运算符及其优先次序 ①<(小于) ②<=(小于或等于) ③>(大于) ④>=(大于或等于 ) ⑤==(等于) ⑥!=(不等于) 说明: 前4个优先级相同,后2个优先级相同,关系运算符的优先级低于算术运算符,关系运算符的优先级高于赋值运算符 1.2关系表达式 用关系运算符将两个表达式(可以是算术表达式或关系表达式,逻辑表达式,赋值表达式,字符

Science|癌症中三级淋巴结构的免疫调节作用与治疗潜力|顶刊精析·24-09-08

小罗碎碎念 Science文献精析 今天精析的这一篇综述,于2022-01-07发表于Science,主要讨论了癌症中的三级淋巴结构(Tertiary Lymphoid Structures, TLS)及其在肿瘤免疫反应中的作用。 作者类型作者姓名单位名称(中文)通讯作者介绍第一作者Ton N. Schumacher荷兰癌症研究所通讯作者之一通讯作者Daniela S. Thomm

ispunct函数讲解 <ctype.h>头文件函数

目录 1.头文件函数 2.ispunct函数使用  小心!VS2022不可直接接触,否则..!没有这个必要,方源一把抓住VS2022,顷刻 炼化! 1.头文件函数 以上函数都需要包括头文件<ctype.h> ,其中包括 ispunct 函数 #include<ctype.h> 2.ispunct函数使用 简述: ispunct函数一种判断字符是否为标点符号的函