目录
前期文章:
流程图拖拽视觉编程--概述_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);
- }
- }
文章
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 - hzt1234hf/FlowChartTools: 使用QT开发的跨平台(Windows、Linux)流程图绘制工具