qchart 绘图

效果图

CustomChartView.h/cpp
#pragma once
#include <QChartView>
#include <QtWidgets/QGraphicsRectItem>
#include <QtWidgets/QGraphicsTextItem>
#include <QtGui/QMouseEvent>
#include <qlineseries.h>
#include <qmath.h>
#include <qscatterseries.h>
#include <qdebug.h>

using namespace QtCharts;

class CustomChartView : public QChartView {
public:
    explicit CustomChartView(QChart* chart, QWidget* parent = nullptr)
        : QChartView(chart, parent), tooltipBox(nullptr), tooltipText(nullptr), hoverDistance(5) {}

protected:

    void resizeEvent(QResizeEvent* event) override {
        // 调用基类的resizeEvent以确保正常的大小调整行为
        QChartView::resizeEvent(event);

        // 更新图例的位置
        if (chart()->legend()) {
            QRectF plotAreaRect = chart()->plotArea();
            chart()->legend()->setGeometry(QRectF(plotAreaRect.right() - 100,
                plotAreaRect.top(),
                100,
                80));
        }
    }


    void mouseMoveEvent(QMouseEvent* event) override {
        QPointF point = chart()->mapToValue(event->pos());
        bool foundPoint = false;
        //考虑根据  <sqrt 1/4*dx^2 +1/4*dy^2 确定
        qreal nearestDistance = hoverDistance;

        foreach(QAbstractSeries * series, chart()->series()) {
            if (auto Scatter = dynamic_cast<QScatterSeries*>(series)) {
                for (const QPointF& dataPoint : Scatter->points()) {
                    qreal distance = qSqrt(qPow(point.x() - dataPoint.x(), 2) + qPow(point.y() - dataPoint.y(), 2));
                    if (distance <= nearestDistance) {
                        foundPoint = true;
                        showTooltip(dataPoint);
                        break;
                    }
                }
                if (foundPoint) break;
            }
        }

        if (!foundPoint) {
            hideTooltip();
        }

        QChartView::mouseMoveEvent(event);
    }

private:
    QGraphicsRectItem* tooltipBox;
    QGraphicsTextItem* tooltipText;
    int hoverDistance; // 鼠标悬停的有效距离

    void showTooltip(const QPointF& point) {
        QString text = QString("X: %1\nY: %2").arg(point.x()).arg(point.y());

        if (!tooltipBox) {
            tooltipBox = new QGraphicsRectItem;
            tooltipBox->setBrush(QBrush(QColor(255, 255, 255))); // 白色背景
            chart()->scene()->addItem(tooltipBox);

            tooltipText = new QGraphicsTextItem;
            chart()->scene()->addItem(tooltipText);
        }

        QFontMetrics metrics(tooltipText->font());
        QRect boundingRect = metrics.boundingRect(text);
        qDebug()<< "metrics.boundingRect(text);"<<metrics.boundingRect(text);
        boundingRect = QRect(5, 5, 60, 40);
        //boundingRect.setTopLeft(QPoint(20, 20));
        tooltipBox->setRect(boundingRect);

        QPointF position = chart()->mapToPosition(point);
        tooltipBox->setPos(position + QPointF(30, -10)); // 调整位置以避免覆盖数据点
        tooltipText->setPlainText(text);
        tooltipText->setPos(position + QPointF(35, -10));
    }

    void hideTooltip() {
        if (tooltipBox) {
            chart()->scene()->removeItem(tooltipBox);
            delete tooltipBox;
            tooltipBox = nullptr;
        }
        if (tooltipText) {
            chart()->scene()->removeItem(tooltipText);
            delete tooltipText;
            tooltipText = nullptr;
        }
    }
};


#include "CustomChartView.h"
//无



QtWidgetsApplication2.h/cpp
#pragma once

#include <QtWidgets/QWidget>
#include "ui_QtWidgetsApplication2.h"

struct PlotPos {
public:
   
    PlotPos(double _x, double _y):x(_x),y(_y)
    {
    
    }

    double x;
    double y;
};

class QtWidgetsApplication2 : public QWidget
{
    Q_OBJECT

public:
    QtWidgetsApplication2(QWidget *parent = nullptr);
    ~QtWidgetsApplication2();

    void init();
private:
    Ui::QtWidgetsApplication2Class ui;
};

#include "QtWidgetsApplication2.h"
#include <QtCharts>
#include <QtCharts/QChartView>
#include <QtCharts/QLineSeries>
#include <QtCharts/QSplineSeries>
#include <QLegend> 
#include <qtimer.h>

#include "CustomChartView.h"

using namespace QtCharts;


QtWidgetsApplication2::QtWidgetsApplication2(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    init();
}

QtWidgetsApplication2::~QtWidgetsApplication2()
{}

void QtWidgetsApplication2::init()
{// 创建一个图表实例
    QChart* chart = new QChart();

    // 假设这是你的两个点集
    std::vector<PlotPos> pointsSet1; // 示例数据,实际应从你的数据源填充
    std::vector<PlotPos> pointsSet2;
    for (int i = 1; i < 100; ++i)
    {
        pointsSet1.push_back(PlotPos(i,i));
        pointsSet2.push_back(PlotPos(i, i+10));
    }    

    QList<QPointF>list,list2;
    list.reserve(pointsSet1.size());
    for (auto& a : pointsSet1)
    {
        list.append(QPointF(a.x, a.y));          
    }
    for (auto& b : pointsSet2)
    {
        list2.append(QPointF(b.x, b.y));
    }
    
    QLineSeries* serial = new QLineSeries(this);//必须要new, 才能实现更新
    QScatterSeries* scatterSeries1 = new QScatterSeries(chart);

    serial->setName("Line 1");//名称
    serial->append(list);//在serial中添加数据
    chart->addSeries(serial);//将数据加载到QChart中
    scatterSeries1->append(list);
    scatterSeries1->setMarkerSize(10); // 设置点的大小
    chart->addSeries(scatterSeries1);
    

    QLineSeries* serial2 = new QLineSeries(this);//必须要new, 才能实现更新
    QScatterSeries* scatterSeries12 = new QScatterSeries(chart);

    serial2->setName("Line 2");//名称
    serial2->append(list2);//在serial中添加数据
    chart->addSeries(serial2);//将数据加载到QChart中
    scatterSeries12->append(list2);
    scatterSeries12->setMarkerSize(10); // 设置点的大小
    chart->addSeries(scatterSeries12);


    chart->createDefaultAxes();//根据数据集,自动创建坐标轴,坐标轴的区间恰好完全容纳已有的数据集
    chart->setTitle("chart");//chart名称
    //chart->setAnimationOptions(QChart::SeriesAnimations);//以动画的形式显示    
    //chart->legend()->setAlignment(Qt::AlignRight);//(图例的位置)
    //chart->legend()->setAlignment(Qt::AlignTop | Qt::AlignRight); // 设置图例对齐方式
    chart->legend()->markers(scatterSeries1).first()->setVisible(false);//屏蔽散点图的图例
    chart->legend()->markers(scatterSeries12).first()->setVisible(false);//屏蔽散点图的图例
    


    //最后需要将chart交给QChartView 
    //QChartView* view = new QChartView(chart);//将chart进行显示
    CustomChartView* view = new CustomChartView(chart);//将chart进行显示
    view->setRenderHint(QPainter::Antialiasing);//消除锯齿
    //view->setFixedSize(600, 600);//chart大小
    
    chart->legend()->detachFromChart();
    chart->legend()->setBackgroundVisible(true);
    chart->legend()->setBrush(QBrush(QColor(128, 128, 128, 128)));
    chart->legend()->setPen(QPen(QColor(192, 192, 192, 192)));

    chart->legend()->setVisible(true);//图例显示
    //chart->legend()->setGeometry(QRectF(chart->plotArea().right() - 100, chart->plotArea().top()+30, 50, 80));
    


    QHBoxLayout* layout = new QHBoxLayout(this);
    layout->addWidget(view);
    this->setLayout(layout);

    //重写resize()事件
    /*QTimer::singleShot(0, view, [chart]() {        
        qDebug() << "Plot Area:" << chart->plotArea();
        chart->legend()->setGeometry(QRectF(chart->plotArea().right() - 100, chart->plotArea().top(), 100, 80));
    });*/
    //qDebug() << "plotArea" << view->plotArea();
    
}


main.cpp

#include "QtWidgetsApplication2.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QtWidgetsApplication2 w;
    w.show();
    return a.exec();
}

posted on 2025-02-27 22:45  不败剑坤  阅读(276)  评论(0)    收藏  举报

导航