#include "chartline.h" #include #include #include #include #include #include ChartLine::ChartLine(QWidget *parent) : QChartView(parent), m_chart(new QChart()), m_axisX(new QValueAxis()), m_axisY(new QValueAxis()), m_lineSeries(new QLineSeries()) { // 设置背景透明 setAttribute(Qt::WA_TranslucentBackground); setStyleSheet("background: transparent;"); m_chart->setBackgroundBrush(Qt::transparent); // 添加坐标轴 m_chart->addAxis(m_axisX, Qt::AlignBottom); m_chart->addAxis(m_axisY, Qt::AlignLeft); // 设置初始坐标轴范围及样式 // 坐标轴 m_axisX->setRange(0, 40); m_axisX->setTickCount(9); m_axisX->setLabelFormat("%.0f"); m_axisX->setTitleFont(QFont("思源黑体", 10)); m_axisX->setTitleBrush(QBrush(QColor("#1D2087"))); m_axisY->setRange(-60, 120); m_axisY->setTickCount(7); m_axisY->setLabelFormat("%.0f"); m_axisY->setTitleFont(QFont("思源黑体", 10)); m_axisY->setTitleBrush(QBrush(QColor("#1D2087"))); // 图表标题 + 隐藏图例 m_chart->setTitleFont(QFont("思源黑体", 10)); m_chart->setTitleBrush(QBrush(QColor("#1D2087"))); m_chart->legend()->hide(); // 设置折线样式 (QLineSeries) QPen linePen(QColor("#4AB832")); linePen.setWidth(1); m_lineSeries->setPen(linePen); m_lineSeries->setName("Combined Line"); m_chart->addSeries(m_lineSeries); m_lineSeries->attachAxis(m_axisX); m_lineSeries->attachAxis(m_axisY); // 隐藏图例 m_chart->legend()->hide(); // 6. 设置网格线样式虚线 QPen gridPen(QColor("#29517E")); gridPen.setWidth(1); gridPen.setStyle(Qt::DashLine); m_axisY->setGridLinePen(gridPen); m_axisX->setGridLineVisible(false); QFont axisFont("思源黑体", 6); // 第二个参数是字号,数值越小,文字越小 m_axisX->setLabelsFont(axisFont); m_axisY->setLabelsFont(axisFont); // 设置图表到 ChartView setChart(m_chart); // PlotArea 边框 m_chart->setPlotAreaBackgroundPen(QPen(QColor("#29517E"), 1, Qt::SolidLine)); m_chart->setPlotAreaBackgroundVisible(true); // 启用抗锯齿 setRenderHint(QPainter::Antialiasing); } void ChartLine::setChartLabels(const QString &chartTitle, const QString &xAxisLabel, const QString &yAxisLabel) { // 设置图表标题 m_chart->setTitle(chartTitle); // 设置 X 轴和 Y 轴标题 m_axisX->setTitleText(xAxisLabel); m_axisY->setTitleText(yAxisLabel); } void ChartLine::addDataSeries(const DataSeries &series) { if (m_dataSeriesMap.contains(series.seriesName)) { qDebug() << "Series already exists:" << series.seriesName; return; } // 存储系列信息 m_dataSeriesMap.insert(series.seriesName, series); // 创建对应的 QScatterSeries QScatterSeries* scatter = new QScatterSeries(); scatter->setName(series.seriesName + "_scatter"); // 隐藏 scatter series markers scatter->setMarkerSize(0.0); scatter->setPen(Qt::NoPen); scatter->setBrush(Qt::NoBrush); // 添加到图表并绑定坐标轴 m_chart->addSeries(scatter); scatter->attachAxis(m_axisX); scatter->attachAxis(m_axisY); // 存储 scatter 系列 m_scatterSeriesMap.insert(series.seriesName, scatter); // 更新散点数据 scatter->replace(series.data); // 创建自定义图标 QList pixmapList; for (const QPointF &point : series.data) { QPointF position = m_chart->mapToPosition(point, m_lineSeries); QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem(series.markerIcon); pixmapItem->setPos(position - QPointF(series.markerIcon.width() / 2, series.markerIcon.height() / 2)); pixmapItem->setParentItem(m_chart); pixmapList.append(pixmapItem); } m_pixmapItemsMap.insert(series.seriesName, pixmapList); // 重新构建折线数据 rebuildLineSeries(); } void ChartLine::removeDataSeries(const QString &seriesName) { if (!m_dataSeriesMap.contains(seriesName)) { qDebug() << "Series does not exist:" << seriesName; return; } // 移除系列信息 m_dataSeriesMap.remove(seriesName); // 移除对应的 scatter 系列 if (m_scatterSeriesMap.contains(seriesName)) { QScatterSeries* scatter = m_scatterSeriesMap.value(seriesName); m_chart->removeSeries(scatter); delete scatter; m_scatterSeriesMap.remove(seriesName); } // 移除并删除自定义图标 if (m_pixmapItemsMap.contains(seriesName)) { for (QGraphicsPixmapItem* pixmap : m_pixmapItemsMap[seriesName]) { m_chart->scene()->removeItem(pixmap); delete pixmap; } m_pixmapItemsMap.remove(seriesName); } // 重新构建折线数据 rebuildLineSeries(); } void ChartLine::updateDataSeries(const QString &seriesName, const QList &data) { if (!m_dataSeriesMap.contains(seriesName)) { qDebug() << "Series does not exist:" << seriesName; return; } // 更新数据 m_dataSeriesMap[seriesName].data = data; // 更新对应的 scatter 系列 if (m_scatterSeriesMap.contains(seriesName)) { QScatterSeries* scatter = m_scatterSeriesMap.value(seriesName); scatter->replace(data); } // 更新自定义图标位置 if (m_pixmapItemsMap.contains(seriesName)) { const QList &pixmaps = m_pixmapItemsMap[seriesName]; QList &seriesData = m_dataSeriesMap[seriesName].data; int minSize = qMin(pixmaps.size(), seriesData.size()); for (int i = 0; i < minSize; ++i) { QPointF position = m_chart->mapToPosition(seriesData[i], m_lineSeries); pixmaps[i]->setPos(position - QPointF(pixmaps[i]->pixmap().width() / 2, pixmaps[i]->pixmap().height() / 2)); } // 移除多余的 pixmap if (pixmaps.size() > seriesData.size()) { for (int i = seriesData.size(); i < pixmaps.size(); ++i) { m_chart->scene()->removeItem(pixmaps[i]); delete pixmaps[i]; } QList updatedList; for (int i = 0; i < seriesData.size(); ++i) { updatedList.append(pixmaps[i]); } m_pixmapItemsMap[seriesName] = updatedList; } // 添加缺失的 pixmap else if (pixmaps.size() < seriesData.size()) { for (int i = pixmaps.size(); i < seriesData.size(); ++i) { QPointF position = m_chart->mapToPosition(seriesData[i], m_lineSeries); QGraphicsPixmapItem *pixmapItem = new QGraphicsPixmapItem(m_dataSeriesMap[seriesName].markerIcon); pixmapItem->setPos(position - QPointF(m_dataSeriesMap[seriesName].markerIcon.width() / 2, m_dataSeriesMap[seriesName].markerIcon.height() / 2)); pixmapItem->setParentItem(m_chart); m_pixmapItemsMap[seriesName].append(pixmapItem); } } } // 重新构建折线数据 rebuildLineSeries(); } void ChartLine::rebuildLineSeries() { // 清空当前折线数据 m_lineSeries->clear(); // 汇总所有数据点 QList allPoints; for (const auto &series : m_dataSeriesMap) { allPoints.append(series.data); } // 排序数据点以确保折线正确 std::sort(allPoints.begin(), allPoints.end(), [](const QPointF &a, const QPointF &b) { return a.x() < b.x(); }); // 添加到折线系列 m_lineSeries->replace(allPoints); // 更新自定义图标位置 updateMarkers(); } void ChartLine::updateMarkers() { for (auto it = m_pixmapItemsMap.begin(); it != m_pixmapItemsMap.end(); ++it) { const QString &seriesName = it.key(); const QList &data = m_dataSeriesMap[seriesName].data; const QList &pixmaps = it.value(); for (int i = 0; i < data.size() && i < pixmaps.size(); ++i) { QPointF position = m_chart->mapToPosition(data[i], m_lineSeries); pixmaps[i]->setPos(position - QPointF(pixmaps[i]->pixmap().width() / 2, pixmaps[i]->pixmap().height() / 2)); } } } void ChartLine::resizeEvent(QResizeEvent *event) { QChartView::resizeEvent(event); updateMarkers(); }