键鼠自动化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

相关文章

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Python基础文件操作方法超详细讲解(详解版)

《Python基础文件操作方法超详细讲解(详解版)》文件就是操作系统为用户或应用程序提供的一个读写硬盘的虚拟单位,文件的核心操作就是读和写,:本文主要介绍Python基础文件操作方法超详细讲解的相... 目录一、文件操作1. 文件打开与关闭1.1 打开文件1.2 关闭文件2. 访问模式及说明二、文件读写1.

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

使用Java实现通用树形结构构建工具类

《使用Java实现通用树形结构构建工具类》这篇文章主要为大家详细介绍了如何使用Java实现通用树形结构构建工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录完整代码一、设计思想与核心功能二、核心实现原理1. 数据结构准备阶段2. 循环依赖检测算法3. 树形结构构建4. 搜索子

Python实现自动化接收与处理手机验证码

《Python实现自动化接收与处理手机验证码》在移动互联网时代,短信验证码已成为身份验证、账号注册等环节的重要安全手段,本文将介绍如何利用Python实现验证码的自动接收,识别与转发,需要的可以参考下... 目录引言一、准备工作1.1 硬件与软件需求1.2 环境配置二、核心功能实现2.1 短信监听与获取2.

利用Python开发Markdown表格结构转换为Excel工具

《利用Python开发Markdown表格结构转换为Excel工具》在数据管理和文档编写过程中,我们经常使用Markdown来记录表格数据,但它没有Excel使用方便,所以本文将使用Python编写一... 目录1.完整代码2. 项目概述3. 代码解析3.1 依赖库3.2 GUI 设计3.3 解析 Mark

Python实现Microsoft Office自动化的几种方式及对比详解

《Python实现MicrosoftOffice自动化的几种方式及对比详解》办公自动化是指利用现代化设备和技术,代替办公人员的部分手动或重复性业务活动,优质而高效地处理办公事务,实现对信息的高效利用... 目录一、基于COM接口的自动化(pywin32)二、独立文件操作库1. Word处理(python-d

Python使用DrissionPage中ChromiumPage进行自动化网页操作

《Python使用DrissionPage中ChromiumPage进行自动化网页操作》DrissionPage作为一款轻量级且功能强大的浏览器自动化库,为开发者提供了丰富的功能支持,本文将使用Dri... 目录前言一、ChromiumPage基础操作1.初始化Drission 和 ChromiumPage

Python实现自动化表单填写功能

《Python实现自动化表单填写功能》在Python中,自动化表单填写可以通过多种库和工具实现,本文将详细介绍常用的自动化表单处理工具,并对它们进行横向比较,可根据需求选择合适的工具,感兴趣的小伙伴跟... 目录1. Selenium简介适用场景示例代码优点缺点2. Playwright简介适用场景示例代码