【项目-】Qt + QCustomPlot 实现频谱监测仪:四图联动、高频信号注入、鼠标交互全解析

四个联动图表(main1/main2 联动,sub3/sub4 联动)

高频信号由外部接口实时传入(X, Y 坐标)

鼠标跟随竖线 + 点击显示坐标

黑底紫轴绿柱的视觉风格

使用 QSplitter 实现可拖动调整大小的 2x2 布局

兼容 Qt Designer UI 文件

项目结构

SpectrumMonitor/

├── SpectrumMonitor.pro

├── main.cpp

├── mainwindow.h

├── mainwindow.cpp

├── mainwindow.ui

├── qcustomplot.h

└── qcustomplot.cpp

  1. .pro 文件
    pro
cpp 复制代码
QT       += core gui widgets
CONFIG   += c++17
TARGET    = SpectrumMonitor
TEMPLATE  = app

SOURCES  += main.cpp \
            mainwindow.cpp \
            qcustomplot.cpp

HEADERS  += mainwindow.h \
            qcustomplot.h

FORMS    += mainwindow.ui

#关键:包含当前目录

INCLUDEPATH += $$PWD

cpp 复制代码
 2. main.cpp
cpp
#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    // 模拟外部高频信号注入(实际项目中由检测算法调用)
    QTimer::singleShot(1500, &w, [&]() {
        w.addHighFreqSignal(250.0, 120.0); // X=250MHz, Y=120
    });
    QTimer::singleShot(3000, &w, [&]() {
        w.addHighFreqSignal(320.5, 95.0);  // X=320.5MHz, Y=95
    });

    return a.exec();
}
cpp 复制代码
 mainwindow.h
cpp
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QCustomPlot>
#include <QCPItemText>
#include <vector>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    // 外部接口:注入高频信号 (X: MHz, Y: 幅度)
    void addHighFreqSignal(double x, double y);

protected:
    bool eventFilter(QObject* obj, QEvent* event) override;

private slots:
    void updateSignalPlots(); // 定时器回调

private:
    void setupPlots();
    void setupSplitter();
    void setupTimers();
    void updateGroupFollowLine(QCustomPlot* plot, double xCoord);
    void clearGroupFollowLines(QCustomPlot* plot);
    double generateSignalPoint(int i);

    Ui::MainWindow *ui;
    QCPItemText* coordLabel;
    QTimer* m_plotTimer;

    // 高频信号队列 (X, Y)
    std::vector<std::pair<double, double>> 

```cpp
m_highFreqQueue;
};
#endif // MAINWINDOW_H
复制代码
 4. mainwindow.cpp

```cpp
cpp
#include "mainwindow.h"
            obj == ui->sub3Plot || obj == ui->sub4Plot) {
            auto e = static_cast<QMouseEvent*>(event);
            QCustomPlot* plot = qobject_cast<QCustomPlot*>(obj);
            double x = plot->xAxis->pixelToCoord(e->pos().x());
            double y = plot->yAxis->pixelToCoord(e->pos().y());
            coordLabel->setText(QString("%1 %2").arg(x, 0, 'f', 1).arg(y, 0, 'f', 2));
            coordLabel->position->setCoords(x, y);
            coordLabel->setVisible(true);
            plot->replot();
            return true;
        }
    }
    return QMainWindow::eventFilter(obj, event);
}

void MainWindow::updateGroupFollowLine(QCustomPlot* plot, double xCoord) {
    // 清除旧线
    for (int i = plot->itemCount() - 1; i >= 0; --i) {
        if (plot->item(i)->inherits("QCPItemLine")) {
            plot->removeItem(plot->item(i));
        }
    }

    // 设置 Y 范围
    double yMax = (plot == ui->main1Plot || plot == ui->sub3Plot) ? 300 : 100;

    // 创建新线
    QCPItemLine* line = new QCPItemLine(plot);
    line->start->setCoords(xCoord, 0);
    line->end->setCoords(xCoord, yMax);
    line->setPen(QPen(Qt::red, 1, Qt::DashLine));
    plot->replot();
}

void MainWindow::clearGroupFollowLines(QCustomPlot* plot) {
    for (int i = plot->itemCount() - 1; i >= 0; --i) {
        if (plot->item(i)->inherits("QCPItemLine")) {
            plot->removeItem(plot->item(i));
        }
    }
    coordLabel->setVisible(false);
    plot->replot();
}
  1. mainwindow.ui 设计要点
    拖入 4 个 QWidget
    提升(Promote)为 QCustomPlot:
    右键 QWidget → Promote to...
    Base class: QWidget
    Promoted class: QCustomPlot
    Header file: qcustomplot.h
    设置 objectName:
    main1Plot, main2Plot, sub3Plot, sub4Plot
    注意:UI 文件中不要设置布局!布局由 setupSplitter() 代码控制。

使用说明

将 qcustomplot.h/.cpp 放在项目根目录

在 Qt Designer 中提升 4 个 QWidget 为 QCustomPlot

编译运行

外部系统调用 addHighFreqSignal(x, y) 注入信号

相关推荐
java1234_小锋8 分钟前
Java高频面试题:SpringBoot为什么要禁止循环依赖?
java·开发语言·面试
铅笔侠_小龙虾14 分钟前
Flutter Demo
开发语言·javascript·flutter
2501_9445255423 分钟前
Flutter for OpenHarmony 个人理财管理App实战 - 账户详情页面
android·java·开发语言·前端·javascript·flutter
福大大架构师每日一题34 分钟前
ComfyUI v0.11.1正式发布:新增开发者专属节点支持、API节点强化、Python 3.14兼容性更新等全方位优化!
开发语言·python
wangdaoyin201035 分钟前
若依vue2前后端分离集成flowable
开发语言·前端·javascript
向阳开的夏天1 小时前
麒麟V10源码编译QT5.6.3 (x86 & arm64)
开发语言·qt
Evand J2 小时前
【MATLAB例程】TOA和TDOA混合定位,适用于二维平面的高精度定位。锚点数量、位置、测量噪声可自行调节
开发语言·matlab·定位·tdoa
念越2 小时前
数据结构:栈堆
java·开发语言·数据结构
方见华Richard2 小时前
递归对抗引擎RAE:AGI终极希望与内生安全范式革新,自指认知AI为碳硅共生必然主体
人工智能·交互·学习方法·原型模式·空间计算
淮北4942 小时前
pip虚拟环境包的问题
开发语言·python·pip