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

Qt使用QGraphicsView绘制线路图————附带详细实现代码

文章目录

  • 0 效果
  • 1 核心
    • 1.1 简单示例
      • 1.1.1 解读
    • 1.2 创建用户交互
      • 1.2.1 完整示例
    • 1.3 创建图形元
      • 1.3.1 绘制直线
      • 1.3.2 绘制贝塞尔曲线
      • 1.3.3 绘制图片
    • 1.4 移动的小车
  • 2 使用自定义视图类
  • 参考

0 效果

视图中包含线路、道岔、信号灯、火车。

下图为站点信号灯:
在这里插入图片描述

下图为区间信号灯:
在这里插入图片描述

下视频为火车过站和区间时,信号灯的改变:
在这里插入图片描述

下图为信号灯的修改:

在这里插入图片描述

下图为道岔的修改:

  • 道岔开:
    在这里插入图片描述
  • 道岔关:
    在这里插入图片描述

1 核心

Qt的Graphics View 框架中,核心就是场景(QGraphicsScene)、视图(QGraphicsView)、图形项(QGraphicsItem)。

引入的头文件为:

#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsRectItem>

1.1 简单示例

	//创建场景QGraphicsScene* m_qgraphicsScene  = new QGraphicsScene;//创建视图QGraphicsView m_graphicsView(m_qgraphicsScene);QGraphicsLineItem* routeLine1 = new QGraphicsLineItem;routeLine1->setPos(QPointF(182, 295));routeLine1->setLine(0,0, 1896-183, 0);routeLine1->setPen(QPen(QColor(125, 200, 235), 4));//添加到场景中m_qgraphicsScene->addItem(routeLine1);m_graphicsView->setGeometry(0, 0, 1910, 580);//实现显示窗口大小m_graphicsView->setGraphicsSceneSceneRect(0, 0, 1920, 580);//设置场景大小m_graphicsView.show();

注意:
1,如果场景的实际大小(宽、高)大于显示窗口大小,就会出现滑动条;否则,就不会出现。
2,可以使用m_graphicsView->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);来进行线段的抗锯齿化;

1.1.1 解读

  • 1, 创建场景
    场景是不可见的,是一个抽象的管理图形项的容器,可向场景中添加图形项,获取场景中的某个图形项等;
QGraphicsScene* m_qgraphicsScene  = new QGraphicsScene;
  • 2 创建视图类
    该类提供绘图的视图(View)组件,用于显示场景中的内容,处理用户的交互操作(如鼠标、键盘事件);
QGraphicsView* m_graphicsView(m_qgraphicsScene);
  • 3 创建图形项目
    QGraphicsLineItem* routeLine1 = new QGraphicsLineItem;routeLine1->setPos(QPointF(182, 295));routeLine1->setLine(0,0, 1896-183, 0);routeLine1->setPen(QPen(QColor(125, 200, 235), 4));//添加到场景中m_qgraphicsScene->addItem(routeLine1);//显示视图	m_graphicsView.show();

1.2 创建用户交互

继承QGraphicsView重写鼠标和键盘事件,代码中使用图标元素的坐标位置来唯一确定图形项:

示例如下:

声明:

protected:/*** @brief mousePressEvent:鼠标点击事件* @param event*/void mousePressEvent(QMouseEvent *event) override;/*** @brief mouseMoveEvent:鼠标移动事件* @param event*/void mouseMoveEvent(QMouseEvent *event) override;    

实现:

//鼠标点击事件
void GraphicsView::mousePressEvent(QMouseEvent *event)
{// 处理鼠标点击事件QPointF pos = mapToScene(event->pos());//转换为场景中的位置QGraphicsItem *item = scene()->itemAt(pos, QTransform());if (item){qDebug()<<"获得图元坐标:"<<item->pos();if(item->type() == 6){//直线}else if(item->type() == 7){//图片for(QMap<LampInformation, int>::Iterator iter = g_lampTypeHash.begin();iter != g_lampTypeHash.end();iter++){//qDebug()<<"判断坐标是否相同";if(iter.key().m_pos == item->pos()){//qDebug()<<"相同";emit changeLampColor2MainInterface(LampInformation(iter.key().m_lampType, iter.key().m_pos, TrainStationInformationNow::ChangdeStationLocated));}}}}else{qDebug() << "Clicked on background";}
}
//鼠标移动事件
void GraphicsView::mouseMoveEvent(QMouseEvent *event)
{// setMouseTracking(true);//QGraphicsView坐标QPoint viewPoint = event->pos();//QGraphicsScene坐标QPointF  scenePoint = mapToScene(viewPoint);QGraphicsItem *item = scene()->itemAt(scenePoint, QTransform());if (item){//qDebug()<<"移动获得图标项目:";if(item->type() == 6){}else if(item->type() == 7){viewport()->setCursor(Qt::PointingHandCursor);}}else{//qDebug() << "没有移动到图标位置";viewport()->setCursor(Qt::ArrowCursor);}
}

1.2.1 完整示例

头文件:

class GraphicsView : public QGraphicsView
{Q_OBJECTpublic:GraphicsView(QWidget *parent = nullptr);//场景QGraphicsScene *m_scene;protected:void mousePressEvent(QMouseEvent *event) override;void mouseMoveEvent(QMouseEvent *event) override;    //鼠标移动事件public:QGraphicsScene* getGraphicsScene();void setGraphicsSceneSceneRect(qreal x, qreal y, qreal w, qreal h);
}

cpp文件:

GraphicsView::GraphicsView(QWidget *parent): QGraphicsView(parent)
{// 创建场景m_scene = new QGraphicsScene(this);//m_scene->setSceneRect(0,0, 1630 , 390 );setScene(m_scene);setMouseTracking(true);// 添加图形项// QGraphicsRectItem *rectItem = new QGraphicsRectItem(0,0, 100, 100);// scene->addItem(rectItem);
}//鼠标点击事件
void GraphicsView::mousePressEvent(QMouseEvent *event)
{// 处理鼠标点击事件QPointF pos = mapToScene(event->pos());//转换为场景中的位置QGraphicsItem *item = scene()->itemAt(pos, QTransform());if (item){qDebug()<<"获得图元坐标:"<<item->pos();if(item->type() == 6){}else if(item->type() == 7){}}else{qDebug() << "Clicked on background";}
}
//鼠标
void GraphicsView::mouseMoveEvent(QMouseEvent *event)
{// setMouseTracking(true);//QGraphicsView坐标QPoint viewPoint = event->pos();//QGraphicsScene坐标QPointF  scenePoint = mapToScene(viewPoint);QGraphicsItem *item = scene()->itemAt(scenePoint, QTransform());if (item){qDebug()<<"移动获得图标项目:"<<item->pos();// viewport()->setCursor(Qt::PointingHandCursor);if(item->type() == 6){}else if(item->type() == 7){viewport()->setCursor(Qt::PointingHandCursor);}}else{//qDebug() << "没有移动到图标位置";viewport()->setCursor(Qt::ArrowCursor);}
}QGraphicsScene *GraphicsView::getGraphicsScene()
{return m_scene;
}void GraphicsView::setGraphicsSceneSceneRect(qreal x, qreal y, qreal w, qreal h)
{m_scene->setSceneRect(x, y, w , h);
}

1.3 创建图形元

1.3.1 绘制直线

    QGraphicsLineItem* routeLine1 = new QGraphicsLineItem;routeLine1->setPos(QPointF(182, 295));routeLine1->setLine(0,0, 1896-183, 0);routeLine1->setPen(QPen(QColor(125, 200, 235), 4));qgraphicsScene->addItem(routeLine1);

1.3.2 绘制贝塞尔曲线

    QPainterPath path;path.moveTo(0, 300);path.cubicTo(0, 300, 16, 266, 32, 266);QGraphicsPathItem* routeLine = new QGraphicsPathItem(path);routeLine->setPen(routeLineItemPassPen);qgraphicsScene->addItem(routeLine);

曲线的计算方法:

在这里插入图片描述

1.3.3 绘制图片

    QGraphicsPixmapItem* lamp1 = new QGraphicsPixmapItem;lamp1->setPos(QPointF(1054, 46));icoPix.load(":/Image/lampMode4Red.png");lamp1->setPixmap(icoPix.scaled(50, 15, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));qgraphicsScene->addItem(lamp1);

1.4 移动的小车

小车使用的是之前博文写的类,这里仅显示对应的头文件,详细内容请查看对应的博文。

#include <QToolButton>
#include <QTimer>class VehicleToolButton : public QToolButton
{Q_OBJECTpublic:/*** @brief 使用默认图片* @param parent*/VehicleToolButton(QWidget *parent = nullptr);/*** @brief VehicleToolButton* @param image:按钮的图标的文件路径* @param size:按钮大小* @param parent*/VehicleToolButton(QString imagePath, QSize size,QWidget *parent = nullptr);~VehicleToolButton();public:/*** @brief 得到速度* @return*/qreal getSpeed();/*** @brief 强制设置显示位置* @param x* @param y*/void setCurCoordinate(int x,int y);/*** @brief 设置现在所处位置* @param x* @param y*/void setCurrentPosition(int x, int y);/*** @brief 改变速度* @param _speed*/void setSpeed(qreal _speed);/*** @brief 设置行进参数* @param _v_point* @param _distance* @param _speed*/void setData(QVector<QPoint> _v_point, qreal _distance, qreal _speed);/*** @brief 设置刷新时间* @param refreshTime*/void setRefreshTime(int refreshTime);/*** @brief 设置图标图片* @param image*/void setImage(QImage image);/*** @brief 设置图标大小* @param size*/void setSize(QSize size);private:/*** @brief 计算从起点到终点方向距离distance的坐标点* @param distance* @param start* @param end* @return*/QPoint getPoswithLinedistance(qreal distance,QPoint start,QPoint end);/*** @brief 按水平轴或者垂直线作镜像翻转,bIsHorizon为true按水平轴,false按垂直方向* @param image* @param bIsHorizon* @return*/QImage filp(const QImage& image,bool bIsHorizon);/*** @brief 根据弧度值(角度值)起点(x1,y1)和终点(x2,y2)确定图片旋转的角度* @param x1* @param y1* @param x2* @param y2*/void setImageRote(int x1,int y1,int x2,int y2);/*** @brief 将图片按顺时针方向旋转一定的角度,fAngle为角度值* @param image* @param fAngle* @return*/QImage rotateImage(const QImage& image,qreal fAngle);/*** @brief 根据弧度值(角度值)r_x,r_y确定图片旋转的角度* @param r_x* @param r_y*/void setImageRote(qreal r_x,qreal r_y);/*** @brief //根据车速和运动轨迹计算time时间之后位置,timer事件调用move()函数移动到该位置,* @param time* @param x* @param y*/void getCurrentPos(qreal time,int& x,int& y);public slots:/*** @brief 刷新图片*/void updatedisplay();/*** @brief 开始定时器* @param _msec*/void startTimer(int _msec);private:QImage m_image;//按钮图标QSize m_pixSize;//按钮大小//车辆行进数据结构QVector<QPoint> m_pointVector;												//行驶路径点集合(图上位置)QVector<qreal> m_linedistanceVector;											//行驶路径段在图上的线段长度qreal m_distance;															//行驶路径总长度(单位m)qreal m_linedistance;														//行驶路径在图上的总长度int	   m_curposindex;														//当前所在点的下标qreal  m_curlinedistance;													//当前所在线段上距离qreal  m_curlinetotledistance;											//当前行驶完成的路径长度总和int	   m_curposx;															//当前在图上的点X坐标int    m_curposy;															//当前在图上的点Y坐标//1km/h ----->0.27777777778m/sqreal m_speed = 0.0;															//当前车速 m/s//设置刷新时间(毫秒)int m_refreshTime = 10;//计时器QTimer m_timer;signals:/*** @brief 停止移动*/void stopVehicleMove();
};

2 使用自定义视图类

1,创建视图类指针:

    GraphicsView* m_graphicsView;

2,调用方法绘图:

    drawGraphicsViewRailwayStation(m_graphicsView);
void MainInterface::drawGraphicsViewRailwayStation(GraphicsView* graphicsView)
{//清除之前的场景元素graphicsView->getGraphicsScene()->clear();//1,创建场景: 场景是不可见的,是一个抽象的管理图形项的容器,可向场景中添加图形项,获取场景中的某个图形项等QGraphicsScene* qgraphicsScene = graphicsView->getGraphicsScene();//3,图形项类(QGraphicsItem)://该类提供了一些基本的图形元件,也可在此基础上自定义图形项,它支持各种事件的响应,如鼠标事件、键盘事件、拖放事件等,以实现图形的交互功能/*------画线路------*/// QPen routeLineItemPassPen(QColor(125, 200, 235), 4);QPen turnoutLinePassPen(QColor(125, 200, 235), 2);QPen routeLineItemPassPen(QColor(125, 200, 235), 4);QPen turnoutLineBlockedPen(Qt::red, 2);QPen routeLineItemBlockedPen(Qt::red, 4);//主干线QGraphicsLineItem* routeLine1 = new QGraphicsLineItem;routeLine1->setPos(QPointF(182, 295));routeLine1->setLine(0,0, 1896-183, 0);routeLine1->setPen(QPen(QColor(125, 200, 235), 4));qgraphicsScene->addItem(routeLine1);QGraphicsLineItem* routeLine2 = new QGraphicsLineItem;routeLine2->setPos(QPointF(4, 358));routeLine2->setLine(0,0, 1896-4, 0);routeLine2->setPen(routeLineItemPassPen);qgraphicsScene->addItem(routeLine2);QGraphicsLineItem* routeLine3 = new QGraphicsLineItem;routeLine3->setPos(QPointF(850, 166));routeLine3->setLine(0,0, 1280 - 850, 0);routeLine3->setPen(routeLineItemPassPen);qgraphicsScene->addItem(routeLine3);//道岔QGraphicsLineItem* turnoutLine1 = new QGraphicsLineItem;turnoutLine1->setPos(QPointF(965, 100));turnoutLine1->setLine(0,0, 1054 - 963, 36 - 103 + 5);turnoutLine1->setPen(turnoutLineBlockedPen);qgraphicsScene->addItem(turnoutLine1);QGraphicsLineItem* turnoutLine2 = new QGraphicsLineItem;turnoutLine2->setPos(QPointF(1274, 36));turnoutLine2->setLine(0,0, 1323 - 1274, 103 - 36 - 3);turnoutLine2->setPen(turnoutLineBlockedPen);qgraphicsScene->addItem(turnoutLine2);QGraphicsLineItem* routeLine5_2 = new QGraphicsLineItem;routeLine5_2->setPos(QPointF(1275, 103));routeLine5_2->setLine(0,0, 1323 - 1275, 0);routeLine5_2->setPen(routeLineItemPassPen);qgraphicsScene->addItem(routeLine5_2);g_turnoutTypeStatusHash[QPair(1274, 36)] = false;g_turnoutRelevanceInformationHash.insert(QPair(1274, 36), TurnoutRelevanceInformation({turnoutLine2}, {routeLine5_2}));QGraphicsLineItem* turnoutLine3 = new QGraphicsLineItem;turnoutLine3->setPos(QPointF(882, 163));turnoutLine3->setLine(0,0, 963 - 882, 103 - 163 + 3);turnoutLine3->setPen(turnoutLineBlockedPen);qgraphicsScene->addItem(turnoutLine3);QGraphicsLineItem* turnoutLine4 = new QGraphicsLineItem;turnoutLine4->setPos(QPointF(1380, 103));turnoutLine4->setLine(0,0, 1460 - 1380, 231 - 103 - 3);turnoutLine4->setPen(turnoutLineBlockedPen);qgraphicsScene->addItem(turnoutLine4);QGraphicsLineItem* routeLine9_4 = new QGraphicsLineItem;routeLine9_4->setPos(QPointF(1380, 231));routeLine9_4->setLine(0,0, 1456 - 1380, 0);routeLine9_4->setPen(routeLineItemPassPen);qgraphicsScene->addItem(routeLine9_4);g_turnoutTypeStatusHash[QPair(1380, 103)] = false;g_turnoutRelevanceInformationHash.insert(QPair(1380, 103), TurnoutRelevanceInformation({turnoutLine4}, {routeLine9_4}));//画灯//QPointF使用qreal(通常是double)来表示坐标,这意味着它可以表示浮点数坐标。而QPoint使用int来表示坐标,只能表示整数坐标QPixmap icoPix;//类型:3、4灯QGraphicsPixmapItem* lamp1 = new QGraphicsPixmapItem;lamp1->setPos(QPointF(1054, 46));icoPix.load(":/Image/lampMode4Red.png");lamp1->setPixmap(icoPix.scaled(50, 15, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));qgraphicsScene->addItem(lamp1);g_lampTypeHash[LampInformation(LampTypeEnum::LampFourType, QPointF(1054, 46), TrainStationInformationNow::StationLocated)] = LampColorTypeEnum::RedLampColorType;m_lampGraphicsPixmapHash[QPair(1054, 46)] = lamp1;QGraphicsPixmapItem* lamp2 = new QGraphicsPixmapItem;lamp2->setPos(QPointF(1210, 12));icoPix.load(":/Image/lampMode3Red.png");lamp2->setPixmap(icoPix.scaled(50, 15, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));qgraphicsScene->addItem(lamp2);g_lampTypeHash[LampInformation(LampTypeEnum::LampThreeType, QPointF(1210, 12), TrainStationInformationNow::StationLocated)] = LampColorTypeEnum::RedLampColorType;m_lampGraphicsPixmapHash[QPair(1210, 12)] = lamp2;}

注意:
1,如果要进行场景切换,则使用graphicsView->getGraphicsScene()->clear();进行场景的清除,而不是removeItem函数;

参考

QGraphicsView架构学习总结

Qt之QGraphicsView入门篇

QT之QGraphicsScene详细介绍

Qt工作笔记-QGraphics框架场景中图元的移除与析构

QPainter、QPen、QBrush,绘图、填充、渐变等使用方法

QGraphicsScene设置SceneRect


http://www.mrgr.cn/news/96582.html

相关文章:

  • 【零基础入门unity游戏开发——2D篇】SpriteRenderer精灵渲染器组件
  • UGNX二次开发——截图功能
  • 蓝桥杯专项复习——二分
  • 将 PyTorch Model 用可视化方法浏览 torchview,onxx, netron, summary | 撰写论文 paper
  • PDF解析黑科技:从OCR-Free到多模态大模型的进化之旅
  • DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加行拖拽排序功能示例14,TableView16_14 拖拽自动保存示例
  • 《异常检测——从经典算法到深度学习》30. 在线服务系统中重复故障的可操作和可解释的故障定位
  • 基于PX4和Ardupilot固件下自定义MAVLink消息测试(QGroundControl和Mission Planner)
  • SQL注入之盲注技术详解
  • DataPlatter:利用最少成本数据提升机器人操控的泛化能力
  • 大模型时代的基础架构 读书笔记
  • Android设计模式之代理模式
  • 项目上传github——SSH连接配置文档
  • 【MySQL】从零开始:掌握MySQL数据库的核心概念(四)
  • 【MySQL】从零开始:掌握MySQL数据库的核心概念(五)
  • Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型多变量回归预测
  • 车载以太网网络测试-25【SOME/IP-报文格式-1】
  • Cocos Creator Shader入门实战(七):RGB不同算法效果的实现,及渲染技术、宏定义、属性参数的延伸配置
  • AIGC1——AIGC技术原理与模型演进:从GAN到多模态融合的突破
  • 01-Docker 安装