Qt 自定义流程图 diagram

前言

本文将对QGraphicsScene, QGraphicsView,QGraphicsItem这三个类进行简单介绍,并通过diagram流程图项目对自定义QGraphicsItem操作进行演示讲解。

程序执行效果

程序主界面
在这里插入图片描述
添加步骤

在这里插入图片描述
步骤删除
在这里插入图片描述
步骤连接
在这里插入图片描述
一键排序
在这里插入图片描述

程序源码下载

gitee

https://gitee.com/jiang_bin_yu/qt-diagram-jby

csdn

https://download.csdn.net/download/qq_37373742/87376898

图形视图框架成员介绍

QGraphicsScene, QGraphicsView,QGraphicsItem,分别是场景、视图和图元
1、场景:
QGraphicsScene场景类完成如下功能:

  • 提供管理大量图元的快速接口
  • 传播事件给场景中的每个图元
  • 管理图元状态,如选择和焦点处理
  • 提供无变换的绘制功能,如打印

2、视图:
QGraphicsView是视图窗口控件, 它使场景的内容可视化。可以连接几个视图到一个场景,也可以为相同的数据集提供几种不同的视口,
QGraphicsView是可滚动的窗口部件,如果需要使用OpenGL,使用QGrphicsView::setViewPort()将视口设置为QGLWidget。
视图接收键盘和鼠标的输入事件,并把它翻译为场景事件(将坐标转换为场景的坐标),使用变换矩阵函数QGraphicsView::matrix()
可以变换场景的坐标,通过这种方法尅实现场景缩放和旋转。QGraphicsView::mapToScene()和QGraphicsView::mapFromScene()将
视图和场景的坐标进行转换。

3、图元:
QGraphicsItem是图元基类,QGraphics View框架提供了几种标准的图元。
如QGraphicsRectItem、QGraphicsEllipseItem,QGraphicsTextItem等,可以继承QGraphicsItem实现符合自己需要的图元。
QGraphicsItem功能:

  • 处理鼠标按下、移动、释放、双击、悬停、滚轮和右键菜单事件
  • 处理键盘输入事件
  • 处理拖放事件
  • 分组
  • 碰撞检测

重写QGraphicsItem

要编写自己的图形项,首先要创建QGraphicsItem的子类,然后从实现它的两个纯虚拟公共函数开始:
**boundingRect()**它返回该项绘制的区域的估计值
**paint()**实现实际绘制。
QGraphicsScene基于boundingRect()建立其项索引,QGraphicsView使用它来剔除不可见项,以及确定绘制重叠项时需要重新编译的区域。此外,QGraphicsItem的碰撞检测机制使用boundingRect()提供有效的截止点
QGraphicScene希望所有boundingRect()和shape()项保持不变,除非通知它。如果要以任何方式更改项的几何图形,必须首先调用prepareGeometryChange()以允许QgraphicsScene更新其记账。

程序源码介绍

在这里插入图片描述
图元:arrow 继承父类 QGraphicsLineItem 功能:绘制步骤箭头
图元:DiagramPixmapItem 继承父类 QGraphicsPixmapItem 功能:功能按钮/流程按钮图元
视图:DiagramView 继承父类QGraphicsView
场景:DiagramScene 继承父类 QGraphicsScene 功能:管理场景内图元

重点代码

实例化功能图元和步骤图元并放在在指定位置

 //功能栏
    for(int i=0; i<4; i++)
    {
        setMode(DiagramScene::InsertItem);

        DiagramPixmapItem* item = new DiagramPixmapItem(m_itemPix.at(i),m_itemName.at(i),QSize(107,157),true);
        QPointF point = QPointF(0+(item->pixmap().width()+27)*i,20);
        connect(item,&DiagramPixmapItem::ItemIsPressed,this,&DiagramScene::slot_itemSelect);

        addItem(item);
        item->setPos(point);
        vParentItems.append(item);
    }
    //步骤栏
    for(int i=4; i<7; i++)
    {
        setMode(DiagramScene::InsertItem);

        DiagramPixmapItem* item = new DiagramPixmapItem(m_itemPix.at(i),m_itemName.at(i),QSize(107,157),true);
        QPointF point = QPointF(0,(item->pixmap().height()+item->getTextHeight()+27)*(i-2)-77);
        connect(item,&DiagramPixmapItem::ItemIsPressed,this,&DiagramScene::slot_itemSelect);

        addItem(item);
        item->setPos(point);
        vParentItems.append(item);
    }

在这里插入图片描述

设置当前功能

功能包含:
InsertItem 插入步骤图元
InsertLine 插入连接箭头图元
MoveItem 移动图元
DeleteItem  删除图元
 enum Mode { InsertItem, InsertLine, MoveItem,DeleteItem };
 //设置当前功能
 void DiagramScene::setMode(Mode mode)
{
    myMode = mode;
}

根据点击功能栏的功能图元执行相应动作

//设置下一次将要添加的步骤
void DiagramScene::slot_itemSelect()
{
    currentSelectItem = (DiagramPixmapItem*)sender();
    if(currentSelectItem->getMyText() == "连接")
    {
        setMode(DiagramScene::InsertLine);
    }
    else if(currentSelectItem->getMyText() == "删除")
    {
        setMode(DiagramScene::DeleteItem);
    }
    else if(currentSelectItem->getMyText() == "移动")
    {
        setMode(DiagramScene::MoveItem);
    }
    else if(currentSelectItem->getMyText() == "一键排序")
    {
        qDebug() << "一键排序";
        setMode(DiagramScene::MoveItem);
        QList<DiagramPixmapItem*> newSortItems;    //根据箭头从新排序
        DiagramPixmapItem* firstItem = nullptr;       //最开始的流程
        //找到最开始的流程
        for(int i=0; i<vEditItems.size(); i++)
        {
            if(vEditItems.at(i)->getArrowSize() == 1)
            {
                Arrow* m_arrow = vEditItems.at(i)->getArrow().at(0);
                if(m_arrow->startItem() == vEditItems.at(i))
                {
                    firstItem = vEditItems.at(i);
                    qDebug() << "开始流程是" << vEditItems.at(i)->getMyText();
                }
            }
        }
        if(firstItem != nullptr)
        {
            SortPixmapItemByArrow(firstItem,&newSortItems); //根据箭头方向按顺序添加item
            //将无箭头的item 添加到 newSortItems后面
            foreach (DiagramPixmapItem* p, vEditItems) {
                if(p->getArrowSize() == 0)
                    newSortItems.append(p);
            }
            vEditItems = newSortItems;
        }

        //根据箭头方向排序
        for(int i=0; i<vEditItems.size(); i++)
        {
            if(i<vPosition.size())
                vEditItems.at(i)->setPos(vPosition.at(i));
        }
    }
    else
        setMode(DiagramScene::InsertItem);
}

通过鼠标事件完成 图元插入 图元连接 图元删除等功能


void DiagramScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    //qDebug() << "press pos" << mouseEvent->scenePos();
    if (mouseEvent->button() != Qt::LeftButton)
        return;
    DiagramItem *item;
    switch (myMode) {
    case InsertItem:{
        if(mouseEvent->scenePos().x() < 200)
        {
            setMode(MoveItem);
            qDebug() << "步骤选择区,不能添加步骤";
            return QGraphicsScene::mousePressEvent(mouseEvent);
        }
        DiagramPixmapItem* item = new DiagramPixmapItem(currentSelectItem->getMyPixmapPath(),currentSelectItem->getMyText(),QSize(107,157));
        connect(item,&DiagramPixmapItem::ItemIsPressed,this,&DiagramScene::slot_itemSelect);
        item->setPos(mouseEvent->scenePos());
        addItem(item);
        vEditItems.append(item);
        if(vEditItems.size() >= 2)
        {
            line = new QGraphicsLineItem(QLineF(vEditItems.at(vEditItems.size()-2)->scenePos(),
                                                vEditItems.at(vEditItems.size()-1)->scenePos()));
            line->setPen(QPen(myLineColor, 2));
        }
        addItem(line);
        autoAddArrow();
        //qDebug() << "insert item at: " << mouseEvent->scenePos();
        hasItemSelected = itemAt(mouseEvent->scenePos(), QTransform()) != nullptr;
        setMode(MoveItem);
        clearAllSelectParentItem();
        break;
    }
    case InsertLine:
    {
        if (itemAt(mouseEvent->scenePos(), QTransform()) == nullptr) break;//绘制线的起始点 没有落在item上则无效
        //父类Item 不画线
        DiagramPixmapItem *pixItem = qgraphicsitem_cast<DiagramPixmapItem *>(itemAt(mouseEvent->scenePos(), QTransform()));
        if(pixItem->isParentFlag())
            return QGraphicsScene::mousePressEvent(mouseEvent);

        line = new QGraphicsLineItem(QLineF(mouseEvent->scenePos(),
                                            mouseEvent->scenePos()));
        line->setPen(QPen(myLineColor, 2));
        addItem(line);
        break;
    }
    case DeleteItem:
    {
        hasItemSelected = itemAt(mouseEvent->scenePos(), QTransform()) != nullptr;
        if(hasItemSelected)
        {
            deleteItems(QList<QGraphicsItem*>() << itemAt(mouseEvent->scenePos(), QTransform()));
        }
        break;
    }
    default:
        hasItemSelected = itemAt(mouseEvent->scenePos(), QTransform()) != nullptr;
    }
    QGraphicsScene::mousePressEvent(mouseEvent);
}
  • 5
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Qt是一个跨平台的应用程序开发框架,具有强大的图形和图像处理功能,非常适合流程图式的开发。在Qt中,可以使用Qt绘图框架和Qt图形视图框架来创建流程图Qt绘图框架提供了绘制基本形状、线条和文本的功能,可以使用贝塞尔曲线、椭圆、矩形等来绘制流程图中的节点和连接线。可以设置节点和连接线的颜色、宽度和样式,以及文本的字体、大小和对齐方式等。通过使用图形项(QGraphicsItem)来表示流程图的每个元素,可以方便地进行位置调整、大小缩放和事件处理等操作。 Qt图形视图框架建立在绘图框架的基础上,提供了用于显示和交互的视图类(QGraphicsView)和场景类(QGraphicsScene)。使用场景类可以管理流程图中的所有图形项,并处理鼠标和键盘事件等交互操作。视图类则负责显示场景,并支持缩放、平移和选中等功能。可以将视图嵌入到Qt应用程序的窗口中,或者作为独立的对话框显示。 基于Qt流程图开发具有许多优势。首先,Qt提供了丰富的绘图和图形处理功能,可以轻松创建出漂亮且高度可定制的流程图。其次,Qt是跨平台的框架,可以在多个操作系统上运行,不受特定平台的限制。此外,Qt具有优秀的性能和稳定性,可以处理各种复杂的图形操作。 总的来说,基于Qt流程图开发是一种方便、灵活且强大的开发方式,可以快速搭建流程图应用,并充分发挥Qt框架的优势。无论是纯粹的流程图应用还是嵌入在其他应用中的流程图功能,Qt都可以满足开发者的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jbyyy、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值