qCustomPlotDemo
使用QCustomPlot实现多窗口绘制数据(支持GPU加速)
qCustomPlotDemo
使用QCustomPlot实现多窗口绘制数据(支持GPU加速)
语言组成
- C++
- 97.3%
- C
- 2.7%
文件结构
查看完整文件清单(128 个文件)
README.md qCustomPlotDemo.sln qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/3dview_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/3dview_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/3dviewd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/3dviewd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/CallbackMaker_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/CallbackMaker_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/CallbackMakerd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/CallbackMakerd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Fractals_random_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Fractals_random_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Fractals_randomd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Fractals_randomd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Fractals_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Fractals_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Fractalsd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Fractalsd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Lorenz_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Lorenz_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Lorenzd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Lorenzd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/One_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/One_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Oned.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/Oned.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/freeglutd.dll qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/freeglutd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/indexed_color_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/indexed_color_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/indexed_colord.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/indexed_colord.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/joystick_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/joystick_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/joystickd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/joystickd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/keyboard_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/keyboard_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/keyboardd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/keyboardd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/multi-touch_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/multi-touch_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/multi-touchd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/multi-touchd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/resizer_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/resizer_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/resizerd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/resizerd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/shapes_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/shapes_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/shapesd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/shapesd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/smooth_opengl3_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/smooth_opengl3_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/smooth_opengl3d.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/smooth_opengl3d.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/spaceball_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/spaceball_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/spaceballd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/spaceballd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/subwin_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/subwin_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/subwind.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/subwind.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/timer_callback_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/timer_callback_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/timer_callbackd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/timer_callbackd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/timer_staticd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/timer_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/timerd.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Debug/timerd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/3dview.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/3dview_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/CallbackMaker.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/CallbackMaker_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/Fractals.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/Fractals_random.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/Fractals_random_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/Fractals_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/Lorenz.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/Lorenz_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/One.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/One_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/freeglut.dll qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/indexed_color.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/indexed_color_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/joystick.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/joystick_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/keyboard.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/keyboard_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/multi-touch.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/multi-touch_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/resizer.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/resizer_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/shapes.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/shapes_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/smooth_opengl3.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/smooth_opengl3_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/spaceball.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/spaceball_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/subwin.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/subwin_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/timer.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/timer_callback.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/timer_callback_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/bin/Release/timer_static.exe qCustomPlotDemo/Freeglut_Windows_3.6.0/include/GL/freeglut.h qCustomPlotDemo/Freeglut_Windows_3.6.0/include/GL/freeglut_ext.h qCustomPlotDemo/Freeglut_Windows_3.6.0/include/GL/freeglut_std.h qCustomPlotDemo/Freeglut_Windows_3.6.0/include/GL/freeglut_ucall.h qCustomPlotDemo/Freeglut_Windows_3.6.0/include/GL/glut.h qCustomPlotDemo/Freeglut_Windows_3.6.0/lib/Debug/freeglut_staticd.lib qCustomPlotDemo/Freeglut_Windows_3.6.0/lib/Debug/freeglut_staticd.pdb qCustomPlotDemo/Freeglut_Windows_3.6.0/lib/Debug/freeglutd.exp qCustomPlotDemo/Freeglut_Windows_3.6.0/lib/Debug/freeglutd.lib qCustomPlotDemo/Freeglut_Windows_3.6.0/lib/Release/freeglut.exp qCustomPlotDemo/Freeglut_Windows_3.6.0/lib/Release/freeglut.lib qCustomPlotDemo/Freeglut_Windows_3.6.0/lib/Release/freeglut_static.lib qCustomPlotDemo/main.cpp qCustomPlotDemo/qCustomPlotDemo.cpp qCustomPlotDemo/qCustomPlotDemo.h qCustomPlotDemo/qCustomPlotDemo.qrc qCustomPlotDemo/qCustomPlotDemo.ui qCustomPlotDemo/qCustomPlotDemo.vcxproj qCustomPlotDemo/qCustomPlotDemo.vcxproj.filters qCustomPlotDemo/qcustomplot.cpp qCustomPlotDemo/qcustomplot.h
关键源码
qCustomPlotDemo/qCustomPlotDemo.h
// 本项目主窗口头文件:定义界面与数据刷新逻辑#pragma once// Qt 基础组件#include <QtWidgets/QWidget>#include <QtCore/QTimer>#include <QtWidgets/QPushButton>#include <QtWidgets/QVBoxLayout>#include <QtWidgets/QHBoxLayout>#include <QtWidgets/QGridLayout>#include <QtGui/QResizeEvent>#include <QtCore/QThread>#include <cmath>#include <QtCore/QRandomGenerator>#include "ui_qCustomPlotDemo.h"#include "qcustomplot.h"QT_BEGIN_NAMESPACEnamespace Ui { class qCustomPlotDemoClass; };QT_END_NAMESPACE/*------------ 数据生成类---------------*/class DataWorker : public QObject{ Q_OBJECTpublic: explicit DataWorker(int graphCount, QObject* parent = nullptr); ~DataWorker();private: int m_lastKey = 0; // 样本索引 int m_graphCount = 0; // 视图数量 QTimer* m_timer = nullptr; // 数据生成定时器////---------------------------------------------------------------------------------------------------------------------------------------////-----------------------------------------------------------------处理(handle)模块------------------------------------------------------////---------------------------------------------------------------------------------------------------------------------------------------public slots: // 暂停生成 void handle_Stop(); // 开始生成 void handle_Start();private slots: // 生成数据 void handle_doGenerate();signals: // 数据就绪 void handle_sendDataReady(int idx, const QVector<double>& keys, const QVector<double>& values, int lastKey);};/*---------- 主窗口类-------------*/class qCustomPlotDemo : public QWidget{ Q_OBJECTpublic: ~qCustomPlotDemo(); qCustomPlotDemo(QWidget *parent = nullptr);private: int m_key = 0; // 样本索引 bool m_running = false; // 运行状态 int m_capPoints = 500000; // 数据上限(超过后替换最旧数据) QThread* m_workerThread = nullptr; // 子线程 Ui::qCustomPlotDemoClass* ui; QVector<QCPGraph*> m_graphs; // 折线图数组 QVector<QCustomPlot*> m_plots; // 绘图控件数组 DataWorker* m_worker = nullptr; // 数据生成器 QPushButton* m_startBtn = nullptr; // 开始按钮 QPushButton* m_pauseBtn = nullptr; // 暂停按钮////---------------------------------------------------------------------------------------------------------------------------------------////-----------------------------------------------------------------初始化(init)模块------------------------------------------------------////---------------------------------------------------------------------------------------------------------------------------------------private: // 初始化信号槽 void init_Connect(); // 初始化主界面 void init_mainWidget(); // 初始化数据生成模块 void init_workerModule();////---------------------------------------------------------------------------------------------------------------------------------------////-----------------------------------------------------------------处理(handle)模块------------------------------------------------------////---------------------------------------------------------------------------------------------------------------------------------------private slots: // 开始生成数据 void handle_startGeneration(); // 暂停生成数据 void handle_pauseGeneration(); // 显示数据 void handle_showData(int idx, const QVector<double>& keys, const QVector<double>& values, int lastKey);};qCustomPlotDemo/qCustomPlotDemo.cpp
#include "qCustomPlotDemo.h"/*------------ 数据生成类---------------*/DataWorker::DataWorker(int graphCount, QObject* parent) : QObject(parent) , m_graphCount(graphCount){}DataWorker::~DataWorker() {}/* 暂停生成*/void DataWorker::handle_Stop(){ if (m_timer && m_timer->isActive()) { m_timer->stop(); }}/* 开始生成*/void DataWorker::handle_Start(){ if (!m_timer) { m_timer = new QTimer(this); m_timer->setInterval(1000); //信号:数据生成定时器触发 槽:生成数据 connect(m_timer, &QTimer::timeout, this, &DataWorker::handle_doGenerate); } if (!m_timer->isActive()) { m_timer->start(); }}/* 生成数据*/void DataWorker::handle_doGenerate(){ const int count = 10000; QVector<double> keys; keys.reserve(count); for (int i = 0; i < count; ++i) { keys.push_back(++m_lastKey); } const double pi = 3.14159265358979323846; for (int idx = 0; idx < m_graphCount; ++idx) { QVector<double> values; values.reserve(count); const double freq = 0.0015 * (1 + idx * 0.3); const double phase = idx * pi / 6.0; for (int i = 0; i < count; ++i) { double x = keys[i]; double v = std::sin(freq * x + phase); v += (QRandomGenerator::global()->bounded(200) - 100) / 100000.0; values.push_back(v); } emit handle_sendDataReady(idx, keys, values, m_lastKey); // 发送数据就绪信号 }}/*---------- 主窗口类-------------*/qCustomPlotDemo::qCustomPlotDemo(QWidget *parent) : QWidget(parent) , ui(new Ui::qCustomPlotDemoClass()){ ui->setupUi(this); init_mainWidget(); init_workerModule(); init_Connect();}qCustomPlotDemo::~qCustomPlotDemo(){ if (m_workerThread) { QMetaObject::invokeMethod(m_worker, "stop", Qt::QueuedConnection); m_workerThread->quit(); m_workerThread->wait(); m_worker->deleteLater(); m_workerThread->deleteLater(); } delete ui;}////---------------------------------------------------------------------------------------------------------------------------------------////-----------------------------------------------------------------初始化(init)模块------------------------------------------------------////---------------------------------------------------------------------------------------------------------------------------------------/* 初始化信号槽*/void qCustomPlotDemo::init_Connect() { //信号:开始按钮被点击 槽:开始生成数据 connect(m_startBtn, &QPushButton::clicked, this, &qCustomPlotDemo::handle_startGeneration); //信号:暂停按钮被点击 槽:暂停生成数据 connect(m_pauseBtn, &QPushButton::clicked, this, &qCustomPlotDemo::handle_pauseGeneration); //信号:数据就绪 connect(m_worker, &DataWorker::handle_sendDataReady, this, &qCustomPlotDemo::handle_showData, Qt::QueuedConnection); // 事件循环起始时再次启用OpenGL与设备像素比,确保上下文有效 QTimer::singleShot(0, this, [this]() { for (auto* p : m_plots) { p->setOpenGl(true, 8); p->replot(QCustomPlot::rpImmediateRefresh); } });}/* 初始化主界面*/void qCustomPlotDemo::init_mainWidget() { // 初始化布局和控件 QHBoxLayout* buttonLayout = new QHBoxLayout(); QVBoxLayout* rootLayout = new QVBoxLayout(this); m_startBtn = new QPushButton(QStringLiteral("开始"), this); m_pauseBtn = new QPushButton(QStringLiteral("暂停"), this); buttonLayout->addWidget(m_startBtn); buttonLayout->addWidget(m_pauseBtn); rootLayout->addLayout(buttonLayout); QGridLayout* grid = new QGridLayout(); rootLayout->addLayout(grid, 1); // 中文名 + 颜色 const QList<QPair<QString, QColor>> series = { {QStringLiteral("红"), QColor(Qt::red)}, {QStringLiteral("蓝"), QColor(Qt::blue)}, {QStringLiteral("紫"), QColor(128, 0, 128)}, {QStringLiteral("绿"), QColor(Qt::green)}, {QStringLiteral("黄"), QColor(Qt::yellow)}, {QStringLiteral("粉"), QColor(255, 182, 193)} }; // 初始化绘图控件 for (int i = 0; i < series.size(); ++i){ QCustomPlot* p = new QCustomPlot(this); // 单个绘图控件 p->setOpenGl(true, 8); p->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); p->legend->setVisible(true); // 显示图例 p->xAxis->setLabel("样本索引"); // X 轴标签 p->setPlottingHint(QCP::phCacheLabels, true); p->xAxis->setRange(0, 1); // 初次绘制范围 p->replot(QCustomPlot::rpImmediateRefresh);// 立即重绘以避免空白 p->yAxis->setRange(-2.0, 2.0); QCPGraph* g = p->addGraph(); // 添加折线图 QPen pen(series[i].second); pen.setWidth(2); g->setPen(pen); g->setName(series[i].first); g->setAdaptiveSampling(true); m_plots.push_back(p); m_graphs.push_back(g); int row = i / 2; int col = i % 2; grid->addWidget(p, row, col); }}/* 初始化数据生成模块*/void qCustomPlotDemo::init_workerModule(){ m_workerThread = new QThread(this); m_worker = new DataWorker(m_graphs.size()); m_worker->moveToThread(m_workerThread); qRegisterMetaType<QVector<double>>("QVector<double>"); m_workerThread->start();}/* 开始生成数据*/void qCustomPlotDemo::handle_startGeneration(){ if (!m_running){ m_running = true; QMetaObject::invokeMethod(m_worker, "handle_Start", Qt::QueuedConnection); }}/* 暂停生成数据*/void qCustomPlotDemo::handle_pauseGeneration(){ m_running = false; QMetaObject::invokeMethod(m_worker, "handle_Stop", Qt::QueuedConnection);}/* 显示数据* idx:X轴索引 keys: values: lastKey:*/void qCustomPlotDemo::handle_showData(int idx, const QVector<double>& keys, const QVector<double>& values, int lastKey){ m_key = lastKey; if (m_key <= m_capPoints) { m_graphs[idx]->addData(keys, values); } else { m_graphs[idx]->data()->removeBefore(m_key - m_capPoints + 1); m_graphs[idx]->addData(keys, values); } double startKey = m_key > m_capPoints ? (m_key - m_capPoints + 1) : 0; m_plots[idx]->xAxis->setRange(startKey, m_key); m_plots[idx]->replot(QCustomPlot::rpQueuedReplot);}qCustomPlotDemo/main.cpp
#include "qCustomPlotDemo.h"#include <QtWidgets/QApplication>int main(int argc, char *argv[]){ QApplication::setAttribute(Qt::AA_UseDesktopOpenGL); // 使用桌面端OpenGL QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);// 共享OpenGL上下文 // 多重采样提升文本与线条质量 QSurfaceFormat fmt; fmt.setSamples(8); QSurfaceFormat::setDefaultFormat(fmt); QApplication a(argc, argv); qCustomPlotDemo w; w.show(); return a.exec();}