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

创建显示心电图的组件

我们把绘制图形部分封装为一个组件,给父组件调用

将 ECGWidget 作为独立组件并不一定需要将其注册为 Qt 的自定义插件或使用 “提升法”。这两种方式通常用于更复杂的场景,而对于大多数内部使用的组件,简单的类继承就足够了。

#ifndef ECGWidget_H
#define ECGWidget_H#include <QWidget>
#include <QJsonArray>
#include "heartdata.h"class ECGWidget : public QWidget
{Q_OBJECT
public:explicit ECGWidget(QWidget *parent = nullptr);// 设置历史数据void setHistoryData(HeartData **channelData);// 更新实时数据void updateRealtimeData(const QList<QByteArray>& newData);// 设置网格密度void setGridDensity(double density) { m_dots = density; }protected:void paintEvent(QPaintEvent *event) override;private:void drawECGGrid(QPainter &painter);void drawECGWave(QPainter &painter, bool isRealtime = false);HeartData *m_channelData[12] = { nullptr }; // 12通道数据QList<QByteArray> m_newData;               // 实时数据bool m_hasRealtimeData = false;            // 是否有实时数据标志double m_dots = 5.0;                       // 网格密度(默认5px)
};#endif // ECGWidget_H

#include "ecgwidget.h"
#include <QPainter>
#include <QFont>ECGWidget::ECGWidget(QWidget *parent): QWidget(parent)
{// 初始化背景色setStyleSheet("background-color: white;");
}void ECGWidget::setHistoryData(HeartData **channelData)
{// 复制通道数据for(int i = 0; i < 12; i++) {if(m_channelData[i]) delete m_channelData[i];m_channelData[i] = new HeartData(*channelData[i]);}update();
}void ECGWidget::updateRealtimeData(const QList<QByteArray>& newData)
{m_newData = newData;m_hasRealtimeData = true;// 更新通道数据for(int i = 0; i < qMin(12, m_newData.size()); i++) {if(m_channelData[i]) {QString data = QString::fromLocal8Bit(m_newData[i]);m_channelData[i]->addData(data.toInt());}}update();
}void ECGWidget::paintEvent(QPaintEvent *event)
{Q_UNUSED(event);QPainter painter(this);// 绘制网格drawECGGrid(painter);// 绘制波形drawECGWave(painter, m_hasRealtimeData);// 绘制标题painter.save();QFont f("Microsoft YaHei", 9, QFont::Bold);painter.setFont(f);painter.setPen(QColor(0, 102, 227));painter.drawText(10, 15, "Channel:12  Speed:25mm/s");painter.restore();
}void ECGWidget::drawECGGrid(QPainter &painter)
{int w = width();int h = height();painter.save();painter.setPen(QColor(247, 250, 250));// 绘制小网格for(int x = 0; x <= w; x += m_dots) {painter.drawLine(x, 0, x, h);}for(int y = 0; y <= h; y += m_dots) {painter.drawLine(0, y, w, y);}// 绘制大网格(5x5小格)painter.setPen(QColor(206, 224, 229));for(int x = 0; x <= w; x += m_dots * 5) {painter.drawLine(x, 0, x, h);}for(int y = 0; y <= h; y += m_dots * 5) {painter.drawLine(0, y, w, y);}painter.restore();
}void ECGWidget::drawECGWave(QPainter &painter, bool isRealtime)
{int w = width();int h = height();int cols = 2;int rows = 6;int rectWidth = w / cols;int rowHeight = h / rows;int middleHeight = rowHeight / 2;// 计算缩放比例 (1mV = 10mm = 10 * dots)float scale = 0.001 * (10 * m_dots); // 转换为像素比例painter.save();painter.setPen(QColor(62, 168, 115));for (int col = 0; col < cols; col++) {for (int row = 0; row < rows; row++) {int index = col * rows + row;if(index >= 12 || !m_channelData[index]) continue;// 获取通道数据QString name = m_channelData[index]->getChannelName();QJsonArray data = m_channelData[index]->getDataArr();// 绘制通道名称painter.drawText(col * rectWidth, row * rowHeight + middleHeight + 25, name);// 绘制波形QVector<QPointF> points;for (int i = 0; i < data.size(); i++) {if (i > rectWidth - m_dots * 2) break;float yPos = row * rowHeight + middleHeight - data[i].toInt() * scale + 25;points.append(QPointF(col * rectWidth + i, yPos));}painter.drawPolyline(points.constData(), points.size());}}painter.restore();
}
在 ecg 类中集成 ECGWidget

ecg 类负责数据管理、串口通信等业务逻辑,并将数据传递给 ECGWidget

// ecg.h
#ifndef ECG_H
#define ECG_H#include <QWidget>
#include <QJsonArray>
#include "heartdata.h"
#include "serialtool.h"
#include "ecgwidget.h" // 包含ECGWidget头文件namespace Ui {
class ecg;
}class ecg : public QWidget
{Q_OBJECTpublic:explicit ecg(QWidget *parent = nullptr);~ecg();void ReadECGFile(QString fileName);void getHistoryData();private slots:void on_closeButton_clicked();void receiveData(); // 串口数据接收槽函数private:Ui::ecg *ui;ECGWidget *m_ecgWidget; // ECG绘图组件QJsonArray m_dataArrs;HeartData *m_channelData[12];SerialTool *m_serial;QList<QByteArray> m_newdata;bool m_serialflag;
};#endif // ECG_H
3. 在 ecg 类中初始化和使用 ECGWidget
// ecg.cpp
#include "ecg.h"
#include "ui_ecg.h"
#include "userdata.h"ecg::ecg(QWidget *parent) :QWidget(parent),ui(new Ui::ecg)
{ui->setupUi(this);// 创建ECGWidget实例并添加到布局中m_ecgWidget = new ECGWidget(this);ui->verticalLayout->addWidget(m_ecgWidget); // 假设UI中有一个verticalLayout// 配置ECGWidgetm_ecgWidget->setGridDensity(5.0);m_ecgWidget->setWaveColor(QColor(62, 168, 115));m_ecgWidget->setChannelLayout(2, 6); // 2列6行布局// 初始化其他组件...ReadECGFile(":/resource/hisdata.txt");serialPortInit();
}// 从文件读取历史数据并传递给ECGWidget
void ecg::ReadECGFile(QString fileName)
{// ... 原有代码 ...getHistoryData();m_ecgWidget->setHistoryData(m_channelData); // 传递数据到ECGWidget
}// 处理串口接收的数据并更新ECGWidget
void ecg::receiveData()
{QByteArray message = m_serial->m_serialport->readAll();m_newdata = message.split(',');m_serialflag = true;// 更新ECGWidget的实时数据m_ecgWidget->updateRealtimeData(m_newdata);
}
4. 信号槽机制优化(可选但推荐)

为了进一步解耦,可以在 ecg 类中添加信号,让 ECGWidget 通过连接信号来接收数据:

// ecg.h
signals:void newECGDataAvailable(const QList<QByteArray>& data);// ecg.cpp
ecg::ecg(QWidget *parent) : QWidget(parent), ui(new Ui::ecg)
{// ... 其他初始化 ...// 连接信号槽connect(this, &ecg::newECGDataAvailable, m_ecgWidget, &ECGWidget::updateRealtimeData);
}void ecg::receiveData()
{// ... 接收数据 ...emit newECGDataAvailable(m_newdata); // 发送信号
}

布局还要调整一下,后面有时间再倒腾吧~~~~~

运行效果?将就一下:

http://www.xdnf.cn/news/15221.html

相关文章:

  • 前端学习4:小白入门注册表单的制作(包括详细思考CSS、JS实现过程)
  • uniapp语音播报天气预报微信小程序
  • 格密码--数学基础--02基变换、幺模矩阵与 Hermite 标准形
  • 从UI设计到数字孪生实战应用:构建智慧金融的风险评估与预警平台
  • 使用 SSH 连接 GitHub
  • 飞算 JavaAI 深度体验:开启 Java 开发智能化新纪元
  • 速学 RocketMQ
  • 基于定制开发开源AI智能名片与S2B2C商城小程序的旅游日志创新应用研究
  • FPGA实现SDI转LVDS视频发送,基于GTX+OSERDES2原语架构,提供2套工程源码和技术支持
  • Maui劝退:用windows直接真机调试iOS,无须和Mac配对
  • leetcode:518. 零钱兑换 II[完全背包]
  • Python 类型注解实战:`Optional` 与安全数据处理的艺术
  • 静态路由综合实验
  • GitHub敏感信息收集与防御指南
  • 人大金仓下载安装教程总结
  • 时间显示 蓝桥云课Java
  • 安卓应用启动崩溃的问题排查记录
  • P1722 矩阵 II 题解 DFS深度优先遍历与卡特兰数(Catalan number)解
  • 【实战】使用 ELK 搭建 Spring Boot Docker 容器日志监控系统
  • 【三维生成】FlashDreamer:基于扩散模型的单目图像到3D场景
  • 力扣-54.螺旋矩阵
  • “Datawhale AI夏令营”基于带货视频评论的用户洞察挑战赛
  • 敏捷测试中的质量闸门如何设置?
  • 【RL-VLM-F】算法框架图绘图学习笔记
  • 【PyTorch】PyTorch中的数据预处理操作
  • Java 与 MySQL 性能优化:MySQL连接池参数优化与性能提升
  • 7月10号总结 (1)
  • HTTP核心基础详解(附实战要点)
  • Android开发中几种scope的对比
  • 【TCP/IP】12. 文件传输协议