四个联动图表(main1/main2 联动,sub3/sub4 联动)
高频信号由外部接口实时传入(X, Y 坐标)
鼠标跟随竖线 + 点击显示坐标
黑底紫轴绿柱的视觉风格
使用 QSplitter 实现可拖动调整大小的 2x2 布局
兼容 Qt Designer UI 文件
项目结构
SpectrumMonitor/
├── main.cpp
├── mainwindow.h
├── mainwindow.cpp
├── mainwindow.ui
├── qcustomplot.h
└── qcustomplot.cpp
- .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();
}
- 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) 注入信号