一、前言
这期算是一次在之前基础上的升级一篇,之前也做过一次热换站系统,不过当时是纯纯手搓版本,老版的视频在某站上有发,如果大家感兴趣,可以去查看。
然后这期依然选择使用 C++ + Qt + QPainter 绘制的方式完成整套热换站远程监控组态界面。结合定时器驱动动画,实现管道介质流动、泵运行状态指示灯、阀门开度、实时数据渲染,完整复刻工业 SCADA 组态监控画面。本文就来拆解这套组态界面的开发思路与实现流程。
二、作品展示
本次实现的是热换站远程监控系统组态画面,完整还原换热站工艺流程:一次网供水回水、板式换热器、循环泵组、补水泵、水箱、各类阀门、压力表传感器,搭配左侧设备状态表格、阀门统计面板、能耗统计面板,右侧实时测点数据面板。先来展示下效果:


项目创意点:
-
背景图炫酷效果
-
管道流体流动动画效果
-
工业风 UI 面板绘制
-
数据驱动绘图,业务解耦
1、背景图炫酷效果
本项目的背景视觉不是单纯靠代码填色实现,而是先设计一张深色科技风背景图,再作为整体底层资源融入 Qt 组态画面。背景图采用深蓝黑主色调,加入渐变光晕、微弱网格、流光线条、局部蓝色辉光等元素,让整个监控系统一打开就具备工业大屏的科技感。
在 Qt 中,背景图作为最底层绘制资源,管道、设备、数据面板都叠加在其上。这样做的好处是:
-
背景效果更丰富,可以实现复杂渐变、光效、纹理和空间感;
-
后期换主题时,只需要替换一张背景图,不需要修改业务逻辑;
-
更接近真实工业监控系统的大屏视觉效果。
但要注意,背景图不宜做得太花,否则会影响上方管道、文字和数据面板的可读性。因此背景整体保持低亮度、低对比,蓝色发光元素集中在边缘和装饰区域,中间工艺流程区域保持干净。
2、管道流体流动动画效果
用 QPainter 实现动态工艺流程,组态画面的核心不只是 "画出来",而是要 "动起来"。本项目通过 QTimer 定时刷新画面,结合 QPainter 分层绘制,实现管道内流体流动效果。
不同介质可以用不同颜色区分(颜色可根据个人喜好来更改):
-
一次网供水:红色或橙红色;
-
二次网循环水:绿色或蓝绿色;
-
回水管道:使用低饱和深色;
-
异常管道:可切换为红色告警色。
3、工业风 UI 面板绘制
项目中的信息面板没有完全依赖 Qt 原生控件,而是使用 QPainter结合背景图来进行手绘实现。
工业风 UI 面板主要包含以下元素:
-
半透明深色面板底;
-
蓝色发光边框;
-
表头高亮条;
-
数据表格分割线;
-
设备状态文字;
-
正常、异常、运行、停止等状态标识。
4、数据驱动绘图,业务解耦
这一点是项目实现工业组态的关键。这个控件通过QWidget来进行提升使用,后期业务整合的时候,可直接增加业务。同时这部分渲染没有把业务逻辑和绘图逻辑混在一起。
三、实现流程
1、主窗口MainWindow
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
timer = new QTimer(this); // 创建定时器对象
static int count = 0;
static bool flag = 0;
static int colorflag = 0;
connect(timer,&QTimer::timeout,
[=]()
{
double randomNumber = QRandomGenerator::global()->generateDouble() * 100; // 生成一个0到99之间的随机数(包括0和99)
ui->widget->Set_TextChangeEvent(count,QString::number(randomNumber,'f',2));
count++;
if(count>9)
{
count = 0;
}
int randomState = QRandomGenerator::global()->bounded(2);
int randomStateID = QRandomGenerator::global()->bounded(6);
//状态控制
ui->widget->Set_TextChangeEvent(stateID[randomStateID],state[randomState]);
//水箱控制
ui->widget->Set_TextChangeEvent(17,QString::number(randomNumber,'f',2));
//指示灯控制
int randomLedID = QRandomGenerator::global()->bounded(12);
static bool ledState = true;
ui->widget->Set_DisplayEvent_IsShow(ledID[randomLedID],ledState = !ledState);
}
);
}
2、核心代码主要在CustomWidget.cpp中
//绘制流动线段
void drawFlowLine(QPainter *painter, QPolygonF points,QColor backgroundColor,
int bgLineWidth,QColor lineColor,int lineWidth,const FlowInfo &flowInfo)
{
QPen pen(backgroundColor);
pen.setJoinStyle(Qt::RoundJoin);
pen.setStyle(Qt::SolidLine);
pen.setWidth(bgLineWidth);
pen.setCapStyle(Qt::RoundCap);
painter->setPen(pen);
painter->drawPolyline(points);
QPen pen1(lineColor);
QVector<qreal> dashes;
qreal space = 2;
dashes << 3 << space << 3 << space;
pen1.setDashPattern(dashes);
pen1.setWidth(lineWidth);
pen1.setJoinStyle(Qt::RoundJoin);
pen1.setCapStyle(Qt::RoundCap);
pen1.setDashOffset(flowInfo.offset);
painter->setPen(pen1);
painter->drawPolyline(points);
}
四、源码开放
大家需要源码去下面位置找我~