Qt 自定义流程图 diagram

news2024/11/26 13:27:37

Qt 自定义流程图 diagram

  • 前言
    • 程序执行效果
    • 程序源码下载
    • 图形视图框架成员介绍
    • 重写QGraphicsItem
    • 程序源码介绍
    • 重点代码

前言

本文将对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);
}

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

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

相关文章

Docker从无到有

随着各个软件的版本越来越多&#xff0c;软件开发、使用环境愈发复杂&#xff0c;Docker日益受到广泛应用。本文记录下从零开始了解、使用docker的各个步骤。 Docker有3个基本概念: Image&#xff0c;镜像。镜像就是系统的快照。静态。每个Image以<Repo Name>:<Tag …

求助:程序员得了结膜炎+干眼症怎么办?

大概是2022年12月初开始&#xff0c;我就感觉眼睛有看东西有点肿胀和模糊&#xff0c;还有就是总想眯眼。本来以为就是用眼过度导致的疲劳&#xff0c;想着周六周日好好休息一下应该就好了&#xff0c;但是没想到不仅没好还加重了。不得已去了医院求助医生。 我去的是杭州的浙…

TS:镜像构建过程中go下载第三方包失败-2023.1.8(已解决)

title: TS&#xff1a;镜像构建过程中go下载第三方包失败-2023.1.8(已解决) date: 2023-1-10 categories: Golang tags:Golang TS&#xff1a;镜像构建过程中go下载第三方包失败-2023.1.8(已解决) 注意&#xff1a;一定要注意项目代码里go版本和自己机器go版本是否一致&#x…

5.2中断系统中的设备树——Linux对中断处理的框架及代码流程简述

当发生中断时&#xff0c;CPU会跳到一个固定的地址去执行代码&#xff0c;这个固定的地址就被称为中断向量。 以ARM920T为例&#xff0c;它的中断向量默认是地址24&#xff08;0x18&#xff09;的地方。那么&#xff0c;就可以在这里放一条跳转指令。 一系列的跳转指令用来处…

基于配置系统和流水线的热更新方案

文章目录背景方案调研具体方案方案优缺点背景 最近我们要在一个新的 App 上增加热更新的能力&#xff0c;按照以往的设计思路&#xff0c;需要后台一起参与&#xff0c;并提供对应的接口&#xff0c;具体的接口如下&#xff1a; 接口参数返回值备注uploadBasePkgappVersion&a…

接口管理工具YApi怎么用?颜值高、易管理、超好用

众多接口管理工具如雨后春笋搬冒出。让人欣慰的是&#xff0c;有许多优秀作品来自国内&#xff0c;包含YApi和rap。看着中文的官网&#xff0c;熟悉的汉语&#xff0c;不禁让人暗爽。当然这也就带来另一个弊端&#xff0c;因为使用基数少&#xff0c;所以参考资料少。我们想学习…

Linux时间的获取与使用

Linux系统时间有两种。 &#xff08;1&#xff09;日历时间。该值是自协调世界时(UTC)1970年1月1日00:00:00这个特定时间以来所经过的秒数累计值。基本数据类型用time_t保存。最后通过转换才能得到我们平时所看到的24小时制或者12小时间制的时间。 &#xff08;2&#xff09;…

使用WSL获得Ubuntu系统环境

文章目录使用WSL获得Ubuntu系统环境为什么要用WSL什么是WSLWSL部署安装Windows Terminal软件使用WSL获得Ubuntu系统环境 为什么要用WSL WSL作为Windows10系统带来的全新特性&#xff0c;正在逐步颠覆开发人员既有的选择。 传统方式获取Linux操作系统环境&#xff0c;是安装完…

凯撒加密Caesar cipher

凯撒加密的由来凯撒加密正是凯撒大帝发明的&#xff0c;是一种古典的加密凯撒率军征服高卢&#xff0c;袭击日耳曼和不列颠&#xff0c;古罗马开启了走出意大利&#xff0c;征服全欧洲的征程仅用8年时间征服高卢后&#xff0c;凯撒率军越过卢比孔河&#xff0c;驱赶政敌&#x…

振弦采集模块参数配置工具的使用

振弦采集模块参数配置工具的使用 通常情况下&#xff0c;在计算机端对模块进行测试、读写时&#xff0c;可使用一些通用的免费工具完成&#xff0c;如基于 MODBUS 通讯协议的调试工具 MODSCAN、通用串口调试助手等&#xff0c; 这些工具可以通过网络搜索下载使用&#xff0c;在…

03【Response、ServletContext】

文章目录03【Response、ServletContext】一、HTTP响应概述1.1 什么是HTTP响应&#xff1a;1.2 响应信息的组成&#xff1a;1.2.1 响应行1.2.2 响应头1.2.3 响应体1.3 Http协议小结二、HttpServletResponse对象2.1 设置响应行2.2.1 设置响应状态码2.2.2 常见响应码1&#xff09;…

入选IDC报告,美创科技数据安全管理平台实力领跑

近日&#xff0c;国际权威研究咨询机构IDC发布《中国数据安全基础设施管理平台市场洞察&#xff0c;2022》报告。本次报告对行业用户以及技术提供商深入访谈&#xff0c;挑选出具有代表性的数据安全基础设施管理平台产品和方案&#xff0c;美创数据安全管理平台入选&#xff0c…

软件测试---概念篇

本文主要介绍软件测试相关的一些基础概念.主要内容包括 : 什么是需求 什么是bug 什么是测试用例 开发模型和测试模型 配置管理和软件测试 一 : 什么是需求 满足用户期望或正式规定文档&#xff08;合同、标准、规范&#xff09;所具有的条件和权能&#xff0c;包含用户需求和软…

【Kubernetes 企业项目实战】02、基于 Prometheus 和 K8s 构建智能化监控告警系统(中)

目录 一、安装和配置 node-exporter 1.1 node-exporter介绍&#xff1f; 1.2 安装 node-exporter 二、Prometheus server 安装和配置 2.1 创建 sa 账号&#xff0c;对 sa 做 rbac 授权 2.2 创建 prometheus 数据存储目录 2.3 安装 Prometheus server 服务 &#xff08;…

Python再入手-03

又过了半年,已经完全忘了当时8月份的python工作了。这半年,先是跑合同,然后张罗出海,完了又搞了两次验收,还做了两次汇报,开了无数的会,忙坏了。 现在,得重新张罗电磁这档子事儿了。下面记录下最近的操作。 1 打开编程环境。 都忘了怎么打开环境了,翻一下以前的博客…

Ant Design使用

目录官网在项目中使用下载引入方法1:全部引入方法2:按需引入-手动加载方法3:按需引入-自动加载组件Anchor作用&#xff1a;用于跳转到页面指定位置案例1-基础使用案例2-添加偏移量案例3-指定容器总结官网 Ant Design官网 在项目中使用 在react中使用Ant Design 下载 使用如…

【无人机学习之Mission Planner】RTK/GPS Inject 学习

█ 【无人机学习之Mission Planner】RTK/GPS Inject 学习 █ 系列文章目录 提示&#xff1a;这里是收集了无人机的相关文章 【无人机学习】无人机基础知识【无人机学习】Mission Planner&#xff08;pc端&#xff09;和QGroundControl&#xff08;android端&#xff09;【无人…

P1102 A-B 数对

题目背景 出题是一件痛苦的事情&#xff01; 相同的题目看多了也会有审美疲劳&#xff0c;于是我舍弃了大家所熟悉的 AB Problem&#xff0c;改用 A-B 了哈哈&#xff01; 题目描述 给出一串正整数数列以及一个正整数 CC&#xff0c;要求计算出所有满足 A - B CA−BC 的数对的…

vb.net多功能白板(集成:绘图,编辑,批注,橡皮,图片处理,拍摄,裁剪,旋转等功能

根据上一次的自定义白板&#xff0c;我已经更新了很多内容了 这一次打算再细一点 初始化程序&#xff1a;所有的整体变量&#xff08;作者提醒&#xff0c;请不要直接照抄代码&#xff0c;可以和作者发的文件进行学习和参考 Public ListOfPen As New List(Of Bitmap)Public L…

ArcGIS如何进行自动矢量化操作

这里我们在网络上找一幅高中地理课本上看的等高线图给大家能进行操作演示。 等高线图 01 地理配准 1、定义投影 给数据框定义一个投影&#xff0c;右键Layers>Properties>Coordinate System>Projected Coordinate Systems>Gauss Kruger>Beijing1954> Be…