当前位置: 首页 > article >正文

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

目录

一、简介

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

三、参考资料


一、简介

前期文章:

流程图拖拽视觉编程--概述_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.kler.cn/a/15571.html

相关文章:

  • 第 17 章 - Go语言 上下文( Context )
  • aws中AcmClient.describeCertificate返回值中没有ResourceRecord
  • stdin文件流指针
  • 平台整合是网络安全成功的关键
  • MySQL-关联查询和子查询
  • 大三学生实习面试经历(1)
  • 解决Oracle11g的SQL Loader(sqlldr)命令行中文乱码问题
  • 分享10个精美可视化模板,解决95%的大屏需求!
  • 荔枝派Zero(全志V3S) tftp下载 kernel 和 nfs 挂载文件系统
  • 嵌入式开发--无刷电机学习1--FOC简介
  • 【DAY46】js的算法(1)
  • Duboo介绍与入门
  • 【Log4j RCE (CVE-2021-44228)】复现及原理分析
  • ASEMI代理ADI亚德诺ADM3051CRZ-REEL7车规级芯片
  • 一款免安装、多平台兼容的 拾色器(Color Picker)
  • C#开发的OpenRA游戏的加载地图流程
  • 【OAI】UERANSIM容器与OAI核心网分立部署及测试
  • 力扣第343场周赛
  • 【Git 入门教程】第七节、Git 远程仓库(Github)
  • MongoDB 聚合管道的输出结果到集合($out)及合并结果到集合($merge)
  • 什么是redis发布订阅模式,并用java代码实现小demo
  • 我们要被淘汰了?从科技变革看"ChatGPT"与"无代码开发"
  • 【数据库数据恢复】ORACLE常见数据灾难的数据恢复可能性分析
  • 【学习笔记】CF607E Cross Sum
  • 前端开发技术——对象
  • apple pencil有买的必要吗?便宜的平替电容笔推荐