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

news2025/1/20 14:48:05

目录

一、简介

二、自定义图元

2.1图元设计

2.2 端口QNEPort

2.3节点块QNEBlock


一、简介

前期文章:

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

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

本期内容:

本期将继续介绍流程编辑器模块的实现方法,前面介绍了视图的实现,现在介绍自定义图元的实现,即流程图中每个节点块、端口和连接线。

二、自定义图元

该部分基于QGraphicsItem 图元类实现,该类提供了一些基本的图形元件,可在此基础上自定义图元。

2.1图元设计

开始:圆角矩形 + 1个输出端口

结束:圆角矩形 + 1个输入端口

程序块:矩形 + 1个输入端口 + 1个输出端口

条件:菱形 + 1个输入端口 + 1个为真端口 + 1个为假端口

 

循环:菱形 + 1个输入端口 + 2个循环体端口 (左+下)+ 1个退出循环端口(右)

流程线:带箭头的直线或者折线

 2.2 端口QNEPort

继承QGraphicsPathItem,设置为圆形

QPainterPath p;
p.addEllipse(-radius_, -radius_, 2 * radius_, 2 * radius_);
setPath(p);
#ifndef QNEPORT_H
#define QNEPORT_H

#include <QGraphicsPathItem>
#include "floweditor_global.h"

class QNEBlock;
class QNEConnection;

/* 端口 */
class FLOWEDITORSHARED_EXPORT QNEPort : public QGraphicsPathItem
{
public:
    enum { Type = QGraphicsItem::UserType + 1 };
    enum E_Direction {TOP = 0, BOTTOM = 1, LEFT = 2, RIGHT = 3};

    QNEPort(QGraphicsItem *parent = 0);
    ~QNEPort();

    void setDirection(const E_Direction &dir);
    E_Direction direction();

    void setOutput(bool b);
    bool isOutput() const;

    void setNEBlock(QNEBlock *);
    QNEBlock *block() const;

    int radius();

    QVector<QNEConnection *> &connections();
    bool isConnected(QNEPort *);

    int type() const
    {
        return Type;
    }
protected:
    QVariant itemChange(GraphicsItemChange change, const QVariant &value);

private:
    QNEBlock *m_block;
    int radius_;
    bool m_isOutput;
    E_Direction m_directtion;
    QVector<QNEConnection *> m_connections;
};

#endif // QNEPORT_H
#include "NEPort.h"

#include <QGraphicsScene>
#include <QFontMetrics>
#include <QPen>
#include <QDebug>

#include "NEConnection.h"

QNEPort::QNEPort(QGraphicsItem *parent):
    QGraphicsPathItem(parent), m_isOutput(false)
{
    radius_ = 5;

    QPainterPath p;
    p.addEllipse(-radius_, -radius_, 2 * radius_, 2 * radius_);
    setPath(p);

    setPen(QPen(Qt::darkRed));
    setBrush(Qt::red);

    setFlag(QGraphicsItem::ItemSendsScenePositionChanges);
}

QNEPort::~QNEPort()
{
    foreach(QNEConnection *conn, m_connections)
    {
        delete conn;
    }
}

void QNEPort::setDirection(const QNEPort::E_Direction &dir)
{
    m_directtion = dir;
}

QNEPort::E_Direction QNEPort::direction()
{
    return m_directtion;
}

void QNEPort::setOutput(bool b)
{
    m_isOutput = b;
}

bool QNEPort::isOutput() const
{
    return m_isOutput;
}

void QNEPort::setNEBlock(QNEBlock *b)
{
    m_block = b;
}

QNEBlock *QNEPort::block() const
{
    return m_block;
}

int QNEPort::radius()
{
    return radius_;
}

QVector<QNEConnection *> &QNEPort::connections()
{
    return m_connections;
}


bool QNEPort::isConnected(QNEPort *other)
{
    qDebug() << "m_connections" << m_connections.size();
    foreach(QNEConnection *conn, m_connections)
        if (conn->port1() == other || conn->port2() == other)
        {
            return true;
        }
    return false;
}

QVariant QNEPort::itemChange(GraphicsItemChange change, const QVariant &value)
{
    if (change == GraphicsItemChange::ItemScenePositionHasChanged)
    {
        foreach(QNEConnection *conn, m_connections)
        {
            conn->updatePosFromPorts();
            conn->updatePath();
        }
    }
    return value;
}

2.3节点块QNEBlock

继承QGraphicsPathItem

#ifndef QNEBLOCK_H
#define QNEBLOCK_H

#include <QFont>
#include <QGraphicsPathItem>
#include "floweditor_global.h"
#include "TypeDefine.h"

class QNEPort;
class QNEConnection;
USE_NAMESPACE_FLOWEDITOR

class FLOWEDITORSHARED_EXPORT QNEBlock : public QGraphicsPathItem
{
public:
    enum { Type = QGraphicsItem::UserType + 3 };

    QNEBlock(QGraphicsItem *parent = 0);

    void setUuid(const QString &uuid);
    QString uuid() const;

    void setName(const QString &name);
    QString name() const;

    void setNodeType(const E_NodeType &type);
    E_NodeType nodeType() const;
    void initBlockByType();

    void setData(const QVariant &data);
    QVariant data() const;

    void setPixmap(const QPixmap &pm);
    void setInitData(const E_NodeType type);

    QMap<QString, QStringList> getNodeStrMap();

    /* 保存加载 */
    void save(T_NodeInfo &);
    void load(const T_NodeInfo &);

    /* 克隆 */
    QNEBlock *clone(int max_uuid);
    QNEBlock *clone(QString uuid_str);

    /* 获得相连的block */
    QNEBlock *getNextBlock(int dir);

    /* 端口 */
    QVector<QNEPort *> ports();
    QNEPort *port(int direction);

    int type() const
    {
        return Type;
    }

    inline int width() const
    {
        return m_width;
    }

    inline int height() const
    {
        return m_height;
    }

    inline QPointF center() const
    {
        return QPointF(m_width / 2, m_height / 2);
    }

protected:
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
    QVariant itemChange(GraphicsItemChange change, const QVariant &value);

private:
    int m_width;
    int m_height;
    E_NodeType m_nodeType;
    QVariant m_data;         /**<  携带数据 */
    QString m_uuid;          /**<  唯一识别码 */
    QString m_name;          /**<  名称 */
    QList<QNEPort *> m_nePortList;
    QFont m_font;
    QPixmap m_pixmap;
    T_NodeInfo m_ni;
    bool m_bIsDrawPixmap;
};

#endif // QNEBLOCK_H

设置路径:QPainterPath, 根据类型添加不同的形状,添加圆角矩形addRoundedRect、添加菱形addPolygon

添加端口:QNEBlock和QNEPort绑定为父子关系new QNEPort(this),QNEBlock位置移动时QNEPort也会跟随移动

void QNEBlock::initBlockByType()
{
    QPainterPath p;
    if(E_NodeType::Start == m_nodeType)
    {
        /* 圆角矩形 */
        p.addRoundedRect(0, 0, m_width, m_height, m_height / 2, m_height / 2);
        // 下
        QNEPort *port = new QNEPort(this);
        port->setPos(m_width / 2, m_height);
        port->setNEBlock(this);
        port->setOutput(true);
        port->setToolTip("Out");
        port->setDirection(QNEPort::BOTTOM);
    }
    else if(E_NodeType::End == m_nodeType)
    {
        /* 圆角矩形 */
        p.addRoundedRect(0, 0, m_width, m_height, m_height / 2, m_height / 2);
        // 上
        QNEPort *port = new QNEPort(this);
        port->setPos(m_width / 2, 0);
        port->setNEBlock(this);
        port->setOutput(false);
        port->setToolTip("In");
        port->setDirection(QNEPort::TOP);
    }
    else if(E_NodeType::Judge == m_nodeType)
    {
        /* 菱形 */
        QPolygonF polygonf;
        polygonf << QPointF(0, m_height / 2)
                 << QPointF(m_width / 2, m_height)
                 << QPointF(m_width, m_height / 2)
                 << QPointF(m_width / 2, 0)
                 << QPointF(0, m_height / 2);
        p.addPolygon(polygonf);

        // 上
        QNEPort *port = new QNEPort(this);
        port->setPos(m_width / 2, 0);
        port->setNEBlock(this);
        port->setOutput(false);
        port->setToolTip("In");
        port->setDirection(QNEPort::TOP);

        // 右
        port = new QNEPort(this);
        port->setPos(m_width, m_height / 2);
        port->setNEBlock(this);
        port->setOutput(true);
        port->setToolTip("Out");
        port->setDirection(QNEPort::RIGHT);

        // 下
        port = new QNEPort(this);
        port->setPos(m_width / 2, m_height);
        port->setNEBlock(this);
        port->setOutput(true);
        port->setToolTip("Out");
        port->setDirection(QNEPort::BOTTOM);
    }
    else if(E_NodeType::Loop == m_nodeType)
    {
        /* 菱形 */
        QPolygonF polygonf;
        polygonf << QPointF(0, m_height / 2)
                 << QPointF(m_width / 2, m_height)
                 << QPointF(m_width, m_height / 2)
                 << QPointF(m_width / 2, 0)
                 << QPointF(0, m_height / 2);
        p.addPolygon(polygonf);

        // 上
        QNEPort *port = new QNEPort(this);
        port->setPos(m_width / 2, 0);
        port->setNEBlock(this);
        port->setOutput(false);
        port->setToolTip("In");
        port->setDirection(QNEPort::TOP);

        // 右
        port = new QNEPort(this);
        port->setPos(m_width, m_height / 2);
        port->setNEBlock(this);
        port->setOutput(true);
        port->setToolTip("Out");
        port->setDirection(QNEPort::RIGHT);

        // 下
        port = new QNEPort(this);
        port->setPos(m_width / 2, m_height);
        port->setNEBlock(this);
        port->setOutput(true);
        port->setToolTip("Out");
        port->setDirection(QNEPort::BOTTOM);

        // 左
        port = new QNEPort(this);
        port->setPos(0, m_height / 2);
        port->setNEBlock(this);
        port->setOutput(false);
        port->setToolTip("In");
        port->setDirection(QNEPort::LEFT);
    }
    else
    {
        /* 圆角矩形 */
        p.addRoundedRect(0, 0, m_width, m_height, 5, 5);

        // 上
        QNEPort *port = new QNEPort(this);
        port->setPos(m_width / 2, 0);
        port->setNEBlock(this);
        port->setOutput(false);
        port->setToolTip("In");
        port->setDirection(QNEPort::TOP);

        // 下
        port = new QNEPort(this);
        port->setPos(m_width / 2, m_height);
        port->setNEBlock(this);
        port->setOutput(true);
        port->setToolTip("Out");
        port->setDirection(QNEPort::BOTTOM);
        m_bIsDrawPixmap = true;
    }
    setPath(p);
}

重写绘图函数paint(), 选中时端口显示port->show(),未选中时端口隐藏port->hide(),绘制路径drawPath、图片drawPixmap、文字drawText

void QNEBlock::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    Q_UNUSED(option)
    Q_UNUSED(widget)

    if (isSelected())
    {
        painter->setPen(QPen(Qt::darkYellow));
        painter->setBrush(Qt::yellow);

        foreach(QGraphicsItem *port_, childItems())
        {
            if (port_->type() == QNEPort::Type)
            {
                port_->show();
            }
        }
    }
    else
    {
        painter->setPen(QPen(Qt::darkGreen));
        painter->setBrush(Qt::green);
        foreach(QGraphicsItem *port_, childItems())
        {
            if (port_->type() == QNEPort::Type)
            {
                port_->hide();
            }
        }
    }

    painter->drawPath(path());

    if(m_bIsDrawPixmap && !m_pixmap.isNull())
    {
        QRect rect(m_height * 0.25, m_height * 0.25, m_height * 0.5, m_height * 0.5);
        painter->drawPixmap(rect, m_pixmap);
    }

    if(!m_name.isEmpty())
    {
        painter->setPen(QPen(Qt::black));
        painter->setBrush(Qt::BrushStyle::NoBrush);
        painter->setFont(m_font);
        QTextOption option(Qt::AlignCenter);
        option.setWrapMode(QTextOption::WordWrap);
        painter->drawText(boundingRect(), m_uuid + m_name, option);
    }
}

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

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

相关文章

【Leetcode】236.二叉树的最近公共祖先

二叉树的最近公共祖先 题目思路1思路2代码 题目 思路1 给我们两个二叉树中的节点 找出里面的最近公共祖先 首先我们要分析p q 两点有哪些位置关系 p q在根节点的两侧 此时最近公共祖先就是根节点 在根节点一侧 此时两个节点都在根节点左侧 此时可以递归二叉树 让root.left…

内存取证小练习-基础训练

这是题目和wolatility2.6的链接 链接&#xff1a;https://pan.baidu.com/s/1wNYJOjLoXMKqbGgpKOE2tg?pwdybww 提取码&#xff1a;ybww --来自百度网盘超级会员V4的分享 压缩包很小&#xff0c;题目也比较简单基础&#xff0c;可以供入门使用 1&#xff1a;Which volatility…

使用auto-gpt来写一篇技术文章(如何部署autogpt+遇到的问题+如何使用)

文章目录 前言一、autogpt本地部署1.clone代码2.启动虚拟环境3.运行项目 二、使用aotogpt生成文章1.人设描述2.设置目标3.文章的生成过程4.文章的生成内容 总结 前言 最近AI技术的发展非常迅猛&#xff0c;尤其是和GPT相关的技术&#xff0c;备受瞩目。近日&#xff0c;Autogp…

nvm安装管理npm

1.根据http://t.csdn.cn/mRwCQ这个教程完成安装 2.使用nvm install [指定版本号]&#xff0c;下载了16.15.1&#xff0c;和10.15.1版本 2.5 这里其实出了一点问题&#xff0c;我在下载16.15.1时&#xff0c;因为墙的问题其实是下载出错&#xff0c;报了一个error的&#xff0c…

手推A Unified Solution to Constrained Bidding in Online Display Advertising论文

A Unified Solution to Constrained Bidding in Online Display Advertising&#xff1a;一种对在线展示广告约束出价问题的通用解决方案 未开放但是可以搜到 NeuralAuction: 电商广告中的端到端机制优化方法 https://arxiv.org/abs/2106.03593 一种使用真负样本的在线延迟反…

JVM,关于JVM基础的知识,你确定不了解一下吗?

目录 一.JVM的概念 什么是JVM&#xff1f; 二.JVM的运行流程 1.class文件如何被JVM加载并运行 2.JVM运行时数据包括哪些区域&#xff08;M&#xff09; 三.类加载的过程&#xff08;M&#xff09; 四.双亲委派模型 1.双亲委派模型分析 2.JAVA中有哪些类加载器&#xf…

Maven私服搭建

为什么要搭建私服 通常在maven项目的pom.xml文件中引入了某个依赖包之后&#xff0c;maven首先会去本地仓库去搜索&#xff0c;本地仓库搜索不到会去maven的配置文件settings.xml中配置的maven镜像地址去找&#xff0c;比如&#xff1a; <mirrors><!-- mirror| Specif…

动态规划 --- 电线布设

动态规划 — 电线布设 题目描述 说是话&#xff0c;刚看到也是很懵逼&#xff0c;不想交子集是什么&#xff1f;乱七八糟的连线。 其实仔细想想后&#xff0c;觉得题目应该是说给定了这些点的连接端点&#xff0c;然后从他给的连线中选择出不想交的且条数最多的连线&#x…

Flink自定义函数之标量函数(UDF函数)

1.背景 flink本身给我们提供了大量的内置函数&#xff0c;已经能满足我们绝大部分的需求&#xff0c;但是如果确实是碰到了一些特殊的场景&#xff0c;无法满足我们的需求的时候&#xff0c;我们可以使用自定义函数来解决。 自定义函数大致可以分为标量函数&#xff08;UDF函…

Linux-安装Python2.7

一、简介 正常情况下&#xff0c;使用sudo apt install python来安装就好了。如果发现这个指令报错了&#xff0c;此时就需要手动安装Python2.7了。例如报错如下&#xff1a; 二、实操 1.下载Python2.7的相关源码&#xff08;以2.7.18为例&#xff09; 下载地址如下&#xff1a…

Linux第四章

文章目录 前言一、快捷键小技巧二、软件安装三、systemctl控制软件启动关闭四、软链接五、日期和时区六、ip地址和主机名七、配置linux固定ip地址八、网络请求和下载九、端口十、进程管理十一、主机状态监控十二、环境变量十三、linux文件的上传和下载十四、压缩和解压总结 前言…

第五章 使用RAID与LVM磁盘阵列技术

第五章 使用RAID与LVM磁盘阵列技术 一、RAID磁盘冗余阵列 1、部署磁盘阵列 &#xff08;1&#xff09;、RAID0、1、5、10方案技术对比 RAID级别最少硬盘可用容量读写性能安全性特点02nn低追求最大容量和速度&#xff0c;任何一块盘损坏&#xff0c;数据全部异常。12n/2n高追…

魔兽世界服务端用户注册以及网页的搭建教程

魔兽世界服务端用户注册以及网页的搭建教程 大家好我是艾西&#xff0c;上一章我们讲解了怎么编译一个魔兽的服务端以及安装最后进到我们自己的游戏。那么在平时娱乐的同时肯定是需要和朋友们一起玩游戏才会更有意思&#xff0c;那么今天艾西教大家怎么搭建用户注册页面以及网…

java进程引发的内存泄露问题排查分析

近期工作过程中遇到了一次容器内存不断增高&#xff0c;最终达到90%引发告警的情况。 特征1&#xff0c;把监控面板时间轴拉长会发现&#xff0c;重启后内存占用78%左右&#xff0c;每天增长1%&#xff0c;大约2周后会涨到90%触发告警&#xff08;即如果2周内有代码发布部署&am…

2022-04-27:用go语言重写ffmpeg的remuxing.c示例。

2022-04-27&#xff1a;用go语言重写ffmpeg的remuxing.c示例。 答案2022-04-27&#xff1a; ffmpeg的remuxing.c是一个用于将多媒体文件从一种容器格式转换为另一种容器格式的命令行工具。它可以将音频、视频和字幕等元素从源文件中提取出来&#xff0c;并按照用户指定的方式…

构造函数和析构函数

1.构造函数 1.1 .构造函数概括 、构造函数是一个特殊的成员函数&#xff0c;名字与类名相同,创建类类型对象时由编译器自动调用&#xff0c;以保证每个数据成员都有 一个合适的初始值&#xff0c;并且在对象整个生命周期内只调用一次。 构造函数是特殊的成员函数&#xff0c…

简单认识 Postman界面操作

查看本文前 您需要先登录Postman 如果还没有处理好 可以先查看我的文章 Postman登录注册指导 右上角的 Home 代表主页 就是我们现在看到的这个界面 Workspaces 是一个工作空间管理 这里 我们选择进入 我的工作空间 之后 我们所有的接口请求 就都是在这一块完成的 Collection…

ubuntu中安装VMware Tools,实现Windows文件拖入Ubuntu

ubantu作为一款非常好用的Linux发行版本&#xff0c;深受广大开发者的喜爱&#x1f603;&#xff0c;为了开发的方便&#xff0c;人们常常在windows电脑中安装VMware虚拟机来运行Linux系统&#xff0c;我们时常会遇到这样一种情况&#xff1a;无法互传虚拟机与主机文件。 原因就…

终端连接工具Tabby的下载、安装与配置

目录 一、终端连接工具Tabby的下载1.1、Tabby的下载地址1.2、Tabby的下载步骤 二、终端连接工具Tabby的安装三、终端连接工具Tabby的SSH连接四、终端连接工具Tabby的SFTP 传输工具4.1、服务器上的文件传输到本地电脑4.2、本地电脑的文件传输到服务器 五、终端连接工具Tabby的设…

基于网络爬虫和SpringBoot框架的晋江文学小说小型网站项目

一、Python网路爬虫技术的设计与实现 Scrapy是一个为了爬取网站数据&#xff0c;提取结构性数据而编写的应用框架&#xff0c;常可以应用在包括数据挖掘&#xff0c;信息处理或存储历史数据等一系列的程序中。项目中&#xff0c;主要采取Scrapy框架实现一个爬虫&#xff0c;抓…