#include "CurvePlotWidget.h" #include using namespace QtCharts; // 只在 cpp 里用,头文件里不要 using // 放在 CurvePlotWidget.cpp 顶部 static void syncChartFontsAndColors(QChart *chart, const QWidget *host) { if (!chart || !host) return; // 1. 坐标轴 for (auto *axis : chart->axes()) { axis->setLabelsFont(host->font()); axis->setLabelsColor(host->palette().color(QPalette::WindowText)); axis->setTitleFont(host->font()); axis->setTitleBrush(QBrush(host->palette().color(QPalette::WindowText))); } // 2. 图例 if (auto *legend = chart->legend()) { legend->setFont(host->font()); legend->setLabelColor(host->palette().color(QPalette::WindowText)); } // 3. 标题(虽然已隐藏,也顺手同步) chart->setTitleFont(host->font()); chart->setTitleBrush(QBrush(host->palette().color(QPalette::WindowText))); } CurvePlotWidget::CurvePlotWidget(QWidget *parent) : QWidget(parent) { initChart(); } void CurvePlotWidget::changeEvent(QEvent *e) { QWidget::changeEvent(e); if (e->type() == QEvent::FontChange || e->type() == QEvent::PaletteChange) syncChartFontsAndColors(m_chart, this); } void CurvePlotWidget::initChart() { m_chart = new QChart; m_chart->setTitle(""); // 无标题 m_chart->setMargins(QMargins(0,0,0,0)); // 关键:外框 0 m_chart->layout()->setContentsMargins(0,0,0,0); m_chart->setBackgroundRoundness(0); m_chart->setBackgroundVisible(false); m_chart->legend()->setVisible(true); // 先隐藏图例,想显示时再 true /* ---------- X 轴:当前时间 ---------- */ m_axisX = new QDateTimeAxis; m_axisX->setFormat("hh:mm:ss"); // 时分秒 m_axisX->setTitleText(""); // 不显示轴标题 m_axisX->setLabelsVisible(true); // 不显示刻度数字 /* ---------- Y 轴 ---------- */ m_axisY = new QValueAxis; m_axisY->setRange(-10, 10); m_axisY->setTitleText(""); // 不显示轴标题 m_axisY->setLabelsVisible(true); // 不显示刻度数字 m_chart->addAxis(m_axisX, Qt::AlignBottom); m_chart->addAxis(m_axisY, Qt::AlignLeft); /* 3. 视图 */ m_view = new QChartView(m_chart); m_view->setRenderHint(QPainter::Antialiasing); m_view->setBackgroundBrush(Qt::NoBrush); m_view->setFrameShape(QFrame::NoFrame); m_view->setContentsMargins(0,0,0,0); // 视图本身无留白 /* 4. 布局 */ QVBoxLayout *lay = new QVBoxLayout(this); lay->setContentsMargins(0,0,0,0); // 父布局无留白 lay->setSpacing(0); // 间距也 0 lay->addWidget(m_view); } int CurvePlotWidget::addSeries(const QString &name, const QColor &color) { QLineSeries *series = new QLineSeries; series->setName(name); series->setColor(color); series->setUseOpenGL(true); m_chart->addSeries(series); series->attachAxis(m_axisX); series->attachAxis(m_axisY); m_series.append(series); return m_series.size() - 1; } void CurvePlotWidget::appendPoint(int seriesIndex, double yValue) { if (seriesIndex < 0 || seriesIndex >= m_series.size()) return; qint64 nowMs = QDateTime::currentMSecsSinceEpoch(); m_series[seriesIndex]->append(nowMs, yValue); // if (m_series[seriesIndex]->count() > MAX_POINTS) // m_series[seriesIndex]->remove(0); updateAxisRange(); } void CurvePlotWidget::updateAxisRange() { qreal minY = 1e9, maxY = -1e9; for (QLineSeries *s : qAsConst(m_series)) { const auto pts = s->pointsVector(); for (const QPointF &p : pts) { minY = qMin(minY, p.y()); maxY = qMax(maxY, p.y()); } } if (minY == 1e9) minY = -10; if (maxY == -1e9) maxY = 10; m_axisY->setRange(minY - 1, maxY + 1); /* X 轴:最近 TIME_WINDOW_S 秒 */ qint64 now = QDateTime::currentMSecsSinceEpoch(); m_axisX->setRange(QDateTime::fromMSecsSinceEpoch(now - TIME_WINDOW_S * 1000), QDateTime::fromMSecsSinceEpoch(now)); }