126 lines
4.0 KiB
C++
126 lines
4.0 KiB
C++
|
|
#include "CurvePlotWidget.h"
|
||
|
|
|
||
|
|
|
||
|
|
#include <QVBoxLayout>
|
||
|
|
|
||
|
|
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));
|
||
|
|
}
|