您现在的位置是:首页 >其他 >流程图拖拽视觉编程-流程编辑器2网站首页其他

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

Jason~shen 2023-06-28 12:00:04
简介流程图拖拽视觉编程-流程编辑器2

目录

一、简介

二、自定义图元

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);
    }
}

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。