一、前言
在电力微网、储能、换电站这类工业监控场景中,经常需要绘制动态电气接线组态图:要展示母线、变压器、PCS、储能电池、换电站、电子公路等设备,还要实现线路通电闪烁、设备状态灯变色、开关通断、实时状态渲染。市面上成熟组态软件固然强大,但定制成本高、二次开发受限。
这次尝试选择 C++ / Qt + QPainter 绘制这套电气接线可视化面板。没有使用第三方组态控件,整套界面完全基于 Qt 框架 + QPainter 绘制,没有使用 QSS 动画、没有外部 UI 组件库。背景图+QPainter来实现效果。自由度极高,配合定时器驱动刷新,实现线路流光、状态灯红绿黄切换,完成微网系统电气接线图的实时可视化。
难点:大量离散图元管理、管线动画性能、坐标映射、设备状态与绘图解耦,既要保证画面工业严谨感,又要动态渲染流畅不卡顿。
二、作品展示
先来上作品进行展示:

开发的核心亮点:
1、纯 QPainter 原生绘制,零第三方组态组件
数据和渲染逻辑分离,每个设备抽象成结构体保存坐标、类型、运行状态,paintEvent 中遍历绘制,便于后续增删设备。
2、电力线路流光动画效果
通电线路实现光点流动动画效果。使用 QTimer 定时触发窗口重绘,维护线路上光点偏移量,在 paintEvent 中批量绘制流动光点;可实现动画逻辑与业务状态解耦,修改设备运行状态就可以直接改变线路渲染效果。
3、多状态图元渲染,状态实时映射画面
指示灯、开关、变压器节点支持多状态渲染:正常绿色、告警黄色,业务层更新设备状态数据,绘图层根据状态枚举自动切换画笔颜色、填充色,不用修改绘图代码。
4、工业风 UI 外壳封装
使用 QPainter 绘制整机面板外壳、铆钉、边框、右侧三色指示灯面板、标题栏 "电气接线图",还原真实工控屏幕质感。底层绘图区域和外壳装饰分层绘制,装饰层不干扰业务图元,方便后续复用外壳到其他监控画面。
5、架构利于扩展
设备、线路都使用数据驱动绘制。后期可以考虑直接对接后端实时数据,把真实微网遥信遥测数据灌入,直接变成真实项目监控界面。
三、实现流程
1、主窗口结构
主窗口MainWindow,右上角放置普通 QPushButton【开始】按钮;中心放置我们自定义的绘图控件CustomWidget(继承自QWidget)
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_Timer = new QTimer(this);
connect(m_Timer,SIGNAL(timeout()),this,SLOT(SlotTimer()));
m_currentFlag = true;
}
2、核心代码
本期的核心代码主要在CustomWidget.cpp中
部分代码展示:
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
# pragma execution_character_set("utf-8")
#endif
void rotateAndPaintRect(QPainter *painter, const QRectF &rect, int angle,bool isRound = false,int rx = 0,int ry = 0)
{
qreal cx = 0;
qreal cy = 0;
cx = rect.center().x();
cy = rect.center().y();
painter->save();
painter->translate(cx ,cy);
painter->rotate(angle);
QPointF drawOffset = rect.topLeft() - QPointF(cx,cy);
painter->drawRect(drawOffset.x(), drawOffset.y(), rect.width(), rect.height());
painter->restore();
}
void DrawText(QPainter &painter,const QRectF &rect,QString str,double angle,int size,QString fontFamily,int textAlignment)
{
QRectF rotatedRect(-rect.width()/2, -rect.height()/2, rect.width(), rect.height());
qreal cx = rect.x() + rect.width() / 2;
qreal cy = rect.y() + rect.height() / 2;
QFont font = QFont(fontFamily, size);
painter.setFont(font);
painter.save();
painter.translate(cx, cy);
painter.scale(1, -1);
painter.rotate(-angle);//旋转角度
painter.drawText(rotatedRect,textAlignment,str);
//恢复上面保存的状态
painter.restore();
}
void DrawImage(QPainter &painter, QImage &image, const QRectF &rect,double angle)
{
QRectF rotatedRect(-rect.width()/2, -rect.height()/2, rect.width(), rect.height());
painter.drawImage(rotatedRect, image);
}
四、源码开放
本期源码开放,有需要的朋友可以去下面位置找我~