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

手写一个基于Qt的轻量级示波器界面,附源码

大家好,今天分享一个轻量级类示波器UI界面,基于Qt+C/C++实现,可轻松处理数十万甚至百万数据点绘制而不卡顿。

因一个项目需要显示高速AD采集的仿真波形,采用普通QChart和QCustomPlot实现时,若前端采集速率拉满,UI界面瞬间卡成PPT。

还要支持缩放、游标测量等功能,用现成控件改起来比较麻烦。

所以我自己基于QPainter + RingBuffer封装了一个轻量级waveWidget。

在Demo中并不是将数据简单地画出来,而是实现了一个接近示波器交互体验的波形显示控件:

  • 支持实时刷新、滚动缓存

  • 普通滚轮:Y轴缩放

  • Ctrl + 滚轮:X轴缩放

  • X轴索引、Y轴数值实时显示

  • Marker测量 ΔX / ΔY

  • 双击窗口放大、缩小功能

  • 支持右键菜单操作,可添加自定义功能

话不多说,先上图看效果:

主界面实时显示(可同时支持多通道)

普通滚轮:Y轴缩放

Ctrl + 滚轮:X轴缩放

双击放大缩小选中窗口

标记测量 ΔX / ΔY

支持右键菜单操作,可添加自定义功能

下面简单讲述下部分实现代码,文章底部提供完整实现源码,可直接拷贝到项目工程使用。

waveWidget继承自QWidget,整个控件可以分成三层:数据层(Buffer)、渲染层(Painter)、交互层(Mouse Event),这三个层次分离得比较清楚,后续扩展会很方便。

在数据处理时抛弃传统的 vector.push_back(),采用环形缓冲区设计,当缓冲区未满时正常写入,缓冲区满则自动覆盖最旧数据。

最大占用内存固定化,写入复杂度 O(1),避免大数据量下性能下降,非常适合高频采样场景。

数据写入显示逻辑:

void WaveWidget::appendData(float value) { m_buffer[m_writePos] = value; m_writePos = (m_writePos + 1) % m_capacity; if (m_count < m_capacity) m_count++; update(); }

主体绘制分为四层:背景、网格、波形、交互元素,比全部塞进 paintEvent 可维护高很多。

drawGrid(p); drawWave(p); drawMarkers(p); drawCursor(p);

对于底层的FPGA研发或信号处理工程师来说,光能看到波形是远远不够的,必须能精确地测量出时序。为此,还重写了鼠标与滚轮事件。

动态缩放:在 wheelEvent 中,监听修饰键,按下Ctrl + 滚轮,修改 m_viewSizeX 进行 X 轴时间基准缩放。纯滚轮则修改 m_yScale 控制 Y 轴幅度比例。所有的缩放都是通过纯数学映射完成,不涉及任何底层数据的重新拷贝。

void WaveWidget::wheelEvent(QWheelEvent *e) { if (e->modifiers() & Qt::ControlModifier) { setXView(m_viewSizeX * ((e->angleDelta().y() > 0) ? 0.8 : 1.25)); } else { setYScale(m_yScale * ((e->angleDelta().y() > 0) ? 1.1 : 0.9)); } }

右键工程菜单与卡尺测量:通过重写 contextMenuEvent ,组件支持呼出原生右键菜单,可以随时在波形上打下两根 X 轴(黄色)或 Y 轴(青色)标记线。

void WaveWidget::contextMenuEvent(QContextMenuEvent *e) { if (!m_contextMenu) { m_contextMenu = new QMenu(this); m_contextMenu->addAction("添加 X 标记", [this]() { if(m_markX.size()>=2) m_markX.clear(); m_markX.append(m_selectedIndex); update(); }); m_contextMenu->addAction("添加 Y 标记", [this]() { if(m_markY.size()>=2) m_markY.clear(); m_markY.append((height()/2.0 - m_mousePos.y())/m_yScale); update(); }); m_contextMenu->addAction("清除标记", [this](){ m_markX.clear(); m_markY.clear(); update(); }); } m_contextMenu->exec(e->globalPos()); }

实时差值计算:在drawMarkers函数中,代码会自动执行 abs( m_markX[1] - m_markX[0]) 计算出X轴的采样点差值,以及利用 fabs(m_markY[1] - m_markY[0])计算出Y轴的幅度差值,并高亮显示在左上角。

void WaveWidget::drawMarkers(QPainter &p) { double xStep = (double)width() / (m_viewSizeX - 1); p.setPen(QPen(Qt::yellow, 1)); for (int lx : m_markX) { double px = width() - (m_count - 1 - lx) * xStep; p.drawLine(px, 0, px, height()); } p.setPen(QPen(Qt::cyan, 1)); for (double vy : m_markY) { double py = height() / 2.0 - vy * m_yScale; p.drawLine(0, py, width(), py); } // 绘制结果文字 p.setPen(Qt::white); if (m_markX.size() == 2) p.drawText(10, 20, QString("ΔX: %1").arg(abs(m_markX[1] - m_markX[0]))); if (m_markY.size() == 2) p.drawText(10, 40, QString("ΔY: %1").arg(fabs(m_markY[1] - m_markY[0]), 0, 'f', 3)); }

双击处理:重载mouseDouble ClickEvent(),当双击时发送信号,把业务逻辑交给外部处理。

void WaveWidget::mouseDoubleClickEvent(QMouseEvent *e) { if (e->button() == Qt::LeftButton) { emit doubleClicked(); // 发出双击信号 } QWidget::mouseDoubleClickEvent(e); }

很多时候,真正好用的工具,不一定复杂,但一定贴近实际需求。在工业级的测控系统与高速数据采集中,性能的瓶颈往往就隐藏在一次不经意的深拷贝,或者一次冗余的屏幕擦除中。掌握了底层 UI 渲染的机制,即使面对 GB/s 的吞吐数据,也能稳如泰山。

嵌入式软硬件系统

专注于嵌入式软硬件相关经验分享、工程实践与技术探索,涵盖单片机、FPGA、PCIe、驱动开发、上位机软件以及测控系统设计等多方面内容。

http://www.jsqmd.com/news/1075727/

相关文章:

  • [1364]bcrypt用法--密码哈希
  • 浏览器中的微信革命:wechat-need-web插件让你随时随地聊天
  • OAuth2 登录与群 Webhook 开放接入
  • JDK 9 的 PlatformClassLoader 只是简单改个名吗?
  • SDKMAN CLI:用 Go 重写版本管理工具的探索
  • 别再死磕SEO!AI时代新流量入口GEO,抢占AI答案推荐位
  • 一键解锁无损音乐宝藏:TIDAL Downloader Next Generation 高解析度音频下载全攻略
  • 博客系统接口需求分析:从模块拆解到自动化测试设计
  • 机器学习小数据训练实战:四维评估与高效落地方法
  • TypedDict 详解与 Dataclass 选型指南
  • 云计算作业3
  • 诊断证明翻译怎么办理?诊断证明翻译怎么线上办理?
  • 真的佩服那些能考上清华北大哈佛的人
  • H3C S5130 交换机 SSH 远程开局配置指南
  • CVE-2018-12613漏洞剖析:从文件包含到代码执行的攻防实战
  • 终极指南:如何用Python快速上手FMI模型仿真
  • LTE-M、NB-IoT、Cat-1 bis:海外部署时应该如何选
  • 16类文本主题分类系统:DistilBERT+ONNX生产实践
  • 27.继电器思维转不过来?读懂 PLC 五层扫描周期,才算真正学会 PLC 编程
  • 豆包大模型2.1 Pro发布深度解析:日均180万亿Token背后的中国AI编程新王座
  • 临时放置代码
  • 中国远程控制行业研究报告(2026):从连接工具到智能生产力基座的演进路径
  • HS2-HF Patch:游戏模组生态系统的架构演进与技术实践
  • 微软详细说明 Windows 11 版本 26H2 的支持生命周期
  • SQL注入漏洞
  • 支持合规二创的AI Remix音乐工具实操分享
  • 好物工具推荐|一站式电商活动查询站点分享
  • 如何理解 CDN 的加速原理?
  • 2026年AI论文写作软件深度评测:6款工具专业水准得分排名
  • Outfit字体:9种字重的开源几何无衬线字体如何重塑现代设计系统