流程图拖拽视觉编程-流程编辑器

news2025/1/20 22:03:02

目录

一、简介

二、流程编辑器-视图实现

三、参考资料


一、简介

前期文章:

流程图拖拽视觉编程--概述_Jason~shen的博客-CSDN博客

本期内容:

本期将介绍流程编辑器模块的实现方法,效果图如下所示。该模块基于QT Graphics/View实现,由视图、自定义图元、图元管理器组成。

二、流程编辑器-视图实现

视图的功能是提供一个节点显示窗口,支持缩放、平移和网格线背景。

该部分继承QGraphicsView实现,定义接口如下:

class GRAPHICSLIBSHARED_EXPORT BaseGraphicsView: public QGraphicsView
{
    Q_OBJECT
public:
    explicit BaseGraphicsView(QWidget *parent = nullptr);
    ~BaseGraphicsView();
    void setFactorMax(double val);     //最大缩放因子
    void setFactorMin(double val);     //最小缩放因子
    void setShowGrid(bool b);          //是否显示网格线
    void setMoveSceneEnabled(bool b);  //是否平移使能

public slots:
    void zoomIn();
    void zoomOut();

protected:
    void wheelEvent(QWheelEvent *event) Q_DECL_OVERRIDE;
    void drawBackground(QPainter *painter, const QRectF &rect) Q_DECL_OVERRIDE;
    void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;
    void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;

private:
    void drawGrid(QPainter *painter, double gridStep);

private:
    double m_factorMax;
    double m_factorMin;
    QPointF m_scenePos;
    QPointF m_pressPos;
    bool m_moveScene;
    bool m_showGrid;
    bool m_moveSceneEnabled;
};

缩放的实现:核心函数scale(), 配合鼠标事件操作,重写鼠标滚动事件函数wheelEvent,限制视图过大或者过小。

void BaseGraphicsView::zoomIn()
{
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    scale(1.2, 1.2);
}

void BaseGraphicsView::zoomOut()
{
    setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
    scale(1 / 1.2, 1 / 1.2);
}

void BaseGraphicsView::wheelEvent(QWheelEvent *event)
{
    qreal factor_out = transform().scale(1.2, 1.2).mapRect(QRectF(0, 0, 1, 1)).width();
    qreal factor_in = transform().scale(1 / 1.2, 1 / 1.2).mapRect(QRectF(0, 0, 1, 1)).width();

    if (event->delta() > 0)
    {
        if(factor_out > m_factorMax)
        {
            return;    /* 防止视图过大 */
        }
        zoomIn();
    }
    else
    {
        if(factor_in < m_factorMin)
        {
            return;    /* 防止视图过小 */
        }
        zoomOut();
    }
    update();
}

平移的实现: 核心函数setSceneRect(),配合鼠标事件操作,重写鼠标按下mousePressEvent、移动mouseMoveEvent、释放mouseReleaseEvent事件函数。

void BaseGraphicsView::mousePressEvent(QMouseEvent *event)
{
    if(m_moveSceneEnabled)
    {
        QMouseEvent fake(event->type(), event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers());
        m_scenePos = mapToScene(event->pos());
        m_pressPos = m_scenePos;

        setDragMode(QGraphicsView::NoDrag);

        if (QApplication::keyboardModifiers() == Qt::ControlModifier &&
                event->button() == Qt::LeftButton)
        {
            setDragMode(QGraphicsView::RubberBandDrag);
        }

        if (event->button() == Qt::MiddleButton)
        {
            setDragMode(QGraphicsView::ScrollHandDrag);
            setInteractive(false);

            event = &fake;

            m_moveScene = true;
        }
        update();
    }
    QGraphicsView::mousePressEvent(event);
}

void BaseGraphicsView::mouseMoveEvent(QMouseEvent *event)
{
    if(m_moveSceneEnabled)
    {
        m_scenePos = mapToScene(event->pos());
        if (m_moveScene)
        {
            QPointF difference = m_pressPos - m_scenePos;
            setSceneRect(sceneRect().translated(difference.x(), difference.y()));
        }
        update();
    }
    QGraphicsView::mouseMoveEvent(event);
}

void BaseGraphicsView::mouseReleaseEvent(QMouseEvent *event)
{
    if(m_moveSceneEnabled)
    {
        QMouseEvent fake(event->type(), event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers());
        if (event->button() == Qt::MiddleButton)
        {
            setDragMode(QGraphicsView::NoDrag);
            setInteractive(true);

            event = &fake;
        }

        m_moveScene = false;
        update();
    }
    QGraphicsView::mouseReleaseEvent(event);
}

网格线背景,通过绘图类QPainter画线,重写绘制背景函数drawBackground

void BaseGraphicsView::drawBackground(QPainter *painter, const QRectF &rect)
{
    QGraphicsView::drawBackground(painter, rect);
    if(m_showGrid)
    {
        QPen pfine(QColor::fromRgb(50, 50, 50), 0.6);

        painter->setPen(pfine);
        drawGrid(painter, 15);

        QPen p(QColor::fromRgb(50, 50, 50), 2.0);

        painter->setPen(p);
        drawGrid(painter, 150);
    }
}

void BaseGraphicsView::drawGrid(QPainter *painter, double gridStep)
{
    QRect   windowRect = rect();
    QPointF tl = mapToScene(windowRect.topLeft());
    QPointF br = mapToScene(windowRect.bottomRight());

    double left   = qFloor(tl.x() / gridStep - 0.5);
    double right  = qFloor(br.x() / gridStep + 1.0);
    double bottom = qFloor(tl.y() / gridStep - 0.5);
    double top    = qFloor(br.y() / gridStep + 1.0);

    for (int xi = int(left); xi <= int(right); ++xi)
    {
        QLineF line(xi * gridStep, bottom * gridStep,
                    xi * gridStep, top * gridStep );

        painter->drawLine(line);
    }

    for (int yi = int(bottom); yi <= int(top); ++yi)
    {
        QLineF line(left * gridStep, yi * gridStep,
                    right * gridStep, yi * gridStep );
        painter->drawLine(line);
    }
}

三、参考资料

文章

GitHub开源推荐 | 节点编辑器-技术圈

python版本

Pavel Křupala / pyqt-node-editor · GitLab

https://blog.csdn.net/mahuatengmmp/category_9948511.html

Release v0.3.1 · beyse/NodeEditor · GitHub

qt4/qt5版本

GitHub - Buanderie/qnodeseditor: Originally from http://algoholic.eu/qnodeseditor-qt-nodesports-based-data-processing-flow-editor/

GitHub - hzt1234hf/FlowChartTools: 使用QT开发的跨平台(Windows、Linux)流程图绘制工具

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/469116.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AVL 树(自平衡二叉搜索树) 介绍

AVL 树&#xff08;自平衡二叉搜索树) 介绍 前言 在介绍二叉搜索树的章节中提到&#xff0c;二叉搜索树可能退化为线性链表&#xff0c;失去作为二叉树的各种优势。那么过程中需要维持二叉树的形式&#xff0c;同时左右子树的深度差异可控&#xff0c;如果能实现这两个条件&a…

要强的董经贵,与跳不出两轮电动车品质“陷阱”的雅迪

文|智能相对论 作者|陈明涛 “雅迪缺乏一个明确的战略定位&#xff0c;整个企业都没有方向&#xff0c;直接导致雅迪在前期竞争中失去先机。” “行业主要竞争对手更擅长销售和价格战&#xff0c;雅迪一直疲于应付、资源消耗大&#xff0c;结果也不理想。” “团队和经销商…

weblogic 反序列化 (CVE-2020-2551)漏洞复现(vulfocus)

漏洞简介 weblogic 反序列化 &#xff08;CVE-2020-2551&#xff09;漏洞是基于IIOP协议执行远程代码进行利用。 启动服务 http://192.168.5.128:10710/console/login/LoginForm.jsp 首先打开此连接&#xff0c;初始化weblogic服务。 准备工具 exp-自己写一个即可. javac…

企业编码生成系统--Python基础项目(4)

1. 成品展示&#x1f697;&#x1f680;&#x1f6eb; 运行&#x1f680;&#x1f680;&#x1f680;&#xff1a;1.在PyCharm中运行《企业编码生成系统》即可进入如图1所示的系统主界面。2.在该界面中可以选择要使用功能对应的菜单进行不同的操作。3.在选择功能菜单时&#x…

搭建electron-vue

electron-vue 准备工作修改package.jsonappveyor.yml.travis.yml.gitignore.eslintrc.js.eslintignore.babelrcsrc/renderer/main.jssrc/renderer/App.vuesrc/renderer/store/index.jssrc/renderer/store/modules/Counter.jssrc/renderer/store/modules/Counter.jssrc/renderer…

GT928 TP驱动跟读及虚拟按键上报解析

目前公司TP常用一套代码。MTK 平台使用.ko形式加载&#xff0c;所以跟读一下加深理解。 static struct i2c_driver tpd_i2c_driver {.driver {.of_match_table of_match_ptr(gt9xx_dt_match),},.probe tpd_i2c_probe,.remove tpd_i2c_remove,.detect tpd_i2c_detect,.dr…

万物皆数,算无止境 | 「雪浪算力开发者大赛」圆满收官

时在中春&#xff0c;阳和方起。 4月23日&#xff0c;「雪浪算力开发者大赛」 在雪浪小镇迎来完美收官。 本次大赛吸引了全球超过2422名开发者&#xff0c; 共有624支企业队伍&#xff0c; 288支高校队伍报名参赛&#xff0c; 累计提交作品9895份。 经过三个月激烈的角逐…

Linux shell编程 循环语句for continue break

for循环是编程语言中一种循环语句 示例1&#xff1a;循环读取user.txt中的用户名&#xff0c;创建用户。设置密码。 for i in $(cat /opt/user.txt) douseradd $iecho 123456 | passwd --stdin $i done 示例2&#xff1a;循环读取ipaddr文本文件中地址&#xff0c;执行ping命令…

基于空间矢量脉宽调制(SVPWM)的并网逆变器研究(Simulink)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

day38—选择题

文章目录 1.在计算机网络中&#xff0c;TCP和UDP协议的相似之处是&#xff08;D&#xff09;2.下列哪项最恰当地描述了建立TCP连接时“第一次握手”所做的工作&#xff08;C&#xff09;3.关于以下 URL 的描述错误的是&#xff08;A&#xff09;4.不属于交换机攻击的是&#xf…

LangChain入门指南

LangChain入门 什么是LangChain如何使用 LangChain&#xff1f;LangChain的模型LangChain 的主要特点使用示例构建语言模型应用程序&#xff1a;LLMPrompt Templates: 管理LLMs的Prompts构建语言模型应用程序&#xff1a;Chat Model完整代码 什么是LangChain LangChain是一个强…

【C语言】leetcode每日一题

目录 前言题目描述题目分析代码描述 前言 时间过得真快&#xff0c;马上又要回家了&#xff0c;马上又要开始卷了。不是每朵鲜花都能代表爱情&#xff0c;但是玫瑰做到了&#xff1b;不是每棵树都能耐得住干渴&#xff0c;但是白杨做到了&#xff1b;不是每个人都在追求上进&a…

【算法思维】-- 动态规划(C++)

OJ须知&#xff1a; 一般而言&#xff0c;OJ在1s内能接受的算法时间复杂度&#xff1a;10e8 ~ 10e9之间&#xff08;中值5*10e8&#xff09;。在竞赛中&#xff0c;一般认为计算机1秒能执行 5*10e8 次计算。 时间复杂度取值范围o(log2n)大的离谱O(n)10e8O(nlog(n))10e6O(nsqrt(…

从CI/CD持续集成部署到DevOps研发运维一体化

今天整理下从传统的CI/CD到DevOps研发运维一体化的整个演进过程。类似于每日构建和冒烟测试&#xff0c;实际上在10多年前就已经在实践&#xff0c;比如当前用的笔记多的AntCruiseControl方式来实现自动化的编译构建和持续集成能力。 包括当前DevOps过程实践中的持续集成&…

基于Springboot的班级综合测评管理系统的设计与实现

摘要 随着互联网技术的高速发展&#xff0c;人们生活的各方面都受到互联网技术的影响。现在人们可以通过互联网技术就能实现不出家门就可以通过网络进行系统管理&#xff0c;交易等&#xff0c;而且过程简单、快捷。同样的&#xff0c;在人们的工作生活中&#xff0c;也就需要…

Android内存泄漏问题排查分析及常见解决方案

什么是内存泄漏&#xff1a; 在Android开发过程中&#xff0c;当一个对象已经不需要再使用了&#xff0c;本该被回收时&#xff0c;而另个正在使用的对象持有它引用从而导致它不能被回收&#xff0c;这就导致本该被回收的对象不能被回收而停留在堆内存中&#xff0c;内存泄漏就…

你真的熟悉多线程的程序的编写?快来查漏补缺

目录 一、Thread 类的属性及常用的构造方法 1.1、 Thread 常见构造方法 1.2、Thread 类的常见属性 1.3、启动&#xff08;创建&#xff09;一个线程 1.4、中断一个线程 1.5、等待一个线程 1.6、休眠当前线程 1.7、当前线程让出的 CPU 资源 二、线程状态 一、Thread 类…

华为OD机试真题(Java),整数编码(100%通过+复盘思路)

一、题目描述 实现一个整数编码方法&#xff0c;使得待编码的数字越小&#xff0c;编码后所占用的字节数越小。 编码规则如下&#xff1a; 编码时7位一组&#xff0c;每个字节的低7位用于存储待编码数字的补码&#xff1b;字节的最高位表示后续是否还有字节&#xff0c;置1表…

2023联网公司时薪排行榜出炉,多多排榜首。微软、美团很强

今天分享一个对于选择公司非常有用的参考&#xff1a;“互联网时薪”。 我们在选择一个公司的时候&#xff0c;往往会比较关注总收入package (除了基本的月薪&#xff0c;加上其他的所有的收入&#xff0c;包括但不限于奖金、股票或股份的分红等等)。 然而&#xff0c;总收入…

算力网络安全

算力网络安全 1. 算力网络简介1.1 基本概念1.2 应用场景 2. 算力网络安全需求3. 算力网络安全架构3.1 算力网络参考架构3.2 资源层安全3.3 控制层和编排管理层安全3.4 服务层安全 4. 算力网络安全关键技术4.1 安全计算4.2 安全编排4.3 数据溯源4.4 可信内生4.5 操作审计4.6 安全…