0


【[Qt]基于QChartView开发的图表显示控件,支持实时显示,动态更新,支持鼠标交互等操作】

[Qt]基于QChartView开发的图表显示控件,支持实时显示,动态更新,支持鼠标交互等操作

前言

这是一个Qt平台的基于QChartView类的图像显示控件,支持鼠标交互,支持数据实时显示,动态更新,坐标轴自适应点集的值,鼠标实时点显示。
实现平台:Windows 10 x64 + Qt 6.2.3 + MSVC 2019 

先来看演示视频

演示视频

控件类关键代码说明

十字线和显示坐标实现

在.h文件中定义十字线lineitem变量和坐标textitem变量

    QGraphicsLineItem *m_xLine;
    QGraphicsLineItem *m_yLine;
    QGraphicsTextItem *m_txtPos;

在Cpp文件中初始化

    m_xLine =newQGraphicsLineItem();
    m_xLine->setPen(QPen(QColor(100,100,100)));
    m_xLine->setZValue(2);

    m_yLine =newQGraphicsLineItem();
    m_yLine->setPen(QPen(QColor(100,100,100)));
    m_yLine->setZValue(2);scene()->addItem(m_xLine);scene()->addItem(m_yLine);

    m_txtPos =newQGraphicsTextItem();
    m_txtPos->setFont(QFont("宋体",15, QFont::Bold));
    m_txtPos->setVisible(false);scene()->addItem(m_txtPos);

然后定义鼠标事件,在鼠标进入时显示,移出时隐藏,移动时显示。

voidChartDrawer::mouseMoveEvent(QMouseEvent *pEvent){
    QPoint point = pEvent->pos();
    m_xLine->setLine(point.x(),0,point.x(),this->height());
    m_yLine->setLine(0,point.y(),this->width(),point.y());
    QPointF chartPoint = m_chart->mapToValue(point);
    m_txtPos->setPlainText(QString("%1,%2").arg(QString::number(chartPoint.x(),'f',3),QString::number(chartPoint.y(),'f',3)));
    m_txtPos->setPos(point.x(), point.y());QChartView::mouseMoveEvent(pEvent);}voidChartDrawer::enterEvent(QEnterEvent *pEvent){
    m_txtPos->setVisible(true);
    m_xLine->setVisible(true);
    m_yLine->setVisible(true);QChartView::leaveEvent(pEvent);}voidChartDrawer::leaveEvent(QEvent *pEvent){
    m_txtPos->setVisible(false);
    m_xLine->setVisible(false);
    m_yLine->setVisible(false);QChartView::leaveEvent(pEvent);}

其他实现请参考具体代码

控件类实现具体代码

ChartDrawer.h文件

#ifndefCHARTDRAWER_H#defineCHARTDRAWER_H#include<QtCharts>#include<QChartView>#include<QWidget>#include<QGraphicsLineItem>#include<QLabel>#include<QGraphicsTextItem>#defineUPDATE_DIS0.001#defineMINOR_TICK_COUNT10#defineTICK_COUNT_MIN5#defineTICK_COUNT_MAX20#defineTICK_DIS_DEFAULT20#defineDEFAULT_X_MIN0#defineDEFAULT_X_MAX10#defineDEFAULT_Y_MIN0#defineDEFAULT_Y_MAX10classChartDrawer:publicQChartView{
    Q_OBJECT
public:explicitChartDrawer(QWidget *parent =nullptr);~ChartDrawer();enumAxisType{
        AxisType_Static =0,
        AxisType_Slide,
        AxisType_Dynamic
    };

    QAbstractSeries::SeriesType getSeriesType();voidaddSeries(QAbstractSeries::SeriesType type = QAbstractSeries::SeriesTypeLine,QString seriesName ="");voidsetSeriesStyle(QString seriesName ="", Qt::GlobalColor color = Qt::red,int width =2);voidsetAxisType(AxisType xType = AxisType_Dynamic);voidsetAxisRange(double xMin,double xMax);voidsetAxisRange(double slideDis);voidsetAxisRange();doublegetXAxisRange();doublegetYAxisRange();voidsetAxisTitle(QString xTitle, QString yTitle);voidsetGridVisible(bool isShow);voidsetLegendVisible(bool isShow);voidsetOriginPointFs(QString seriesName, QList<QPointF>);voidaddPointF(QString seriesName, QPointF);voidclearAllPointF();staticboolcompareX(QPointF a, QPointF b);staticboolcompareY(QPointF a, QPointF b);virtualvoidmousePressEvent(QMouseEvent *pEvent)override;virtualvoidmouseReleaseEvent(QMouseEvent *pEvent)override;virtualvoidwheelEvent(QWheelEvent *pEvent)override;virtualvoidmouseMoveEvent(QMouseEvent *e)override;virtualvoidenterEvent(QEnterEvent *pEvent)override;virtualvoidleaveEvent(QEvent *pEvent)override;

    QChart          *m_chart;
    QValueAxis      *m_xAxis;
    QValueAxis      *m_yAxis;
    QGraphicsLineItem *m_xLine;
    QGraphicsLineItem *m_yLine;
    QGraphicsTextItem *m_txtPos;

    QMap<QString, QXYSeries*>  m_mapSeries;
    QAbstractSeries::SeriesType m_seriesType;
    AxisType m_xAxisType = AxisType_Dynamic;double m_xMin, m_xMax, m_yMin, m_yMax;double m_slideDis;bool m_middleButtonPressed =false;
    QPoint m_oPrePos;};#endif// CHARTDRAWER_H

ChartDrawer.cpp 文件

#include"chartdrawer.h"ChartDrawer::ChartDrawer(QWidget *parent): QChartView{parent},m_xMin(0.0),m_xMax(10),m_yMin(0.0),m_yMax(10){
    m_chart =newQChart();this->setChart(m_chart);this->setRubberBand(QChartView::NoRubberBand);this->setRenderHint(QPainter::Antialiasing);this->setContentsMargins(0,0,0,0);//m_chart->setTheme(QChart::ChartThemeDark);

    m_xAxis =new QValueAxis;
    m_xAxis->setLabelFormat("%.3f");
    m_xAxis->setRange(m_xMin,m_xMax);

    m_yAxis =new QValueAxis;
    m_yAxis->setLabelFormat("%.3f");
    m_yAxis->setRange(m_yMin,m_yMax);

    m_chart->addAxis(m_xAxis, Qt::AlignBottom);
    m_chart->addAxis(m_yAxis, Qt::AlignLeft);

    m_xLine =newQGraphicsLineItem();
    m_xLine->setPen(QPen(QColor(100,100,100)));
    m_xLine->setZValue(2);

    m_yLine =newQGraphicsLineItem();
    m_yLine->setPen(QPen(QColor(100,100,100)));
    m_yLine->setZValue(2);scene()->addItem(m_xLine);scene()->addItem(m_yLine);

    m_txtPos =newQGraphicsTextItem();
    m_txtPos->setFont(QFont("宋体",15, QFont::Bold));
    m_txtPos->setVisible(false);scene()->addItem(m_txtPos);}ChartDrawer::~ChartDrawer(){deleteLater();delete m_xLine;delete m_yLine;delete m_txtPos;
    m_xLine =nullptr;
    m_yLine =nullptr;
    m_txtPos =nullptr;}
QAbstractSeries::SeriesType ChartDrawer::getSeriesType(){return m_seriesType;}voidChartDrawer::addSeries(QAbstractSeries::SeriesType type,QString seriesName){
    m_seriesType = type;
    QXYSeries *series;switch(type){case QAbstractSeries::SeriesType::SeriesTypeLine:
        series =newQLineSeries(this);break;case QAbstractSeries::SeriesType::SeriesTypeSpline:
        series =newQSplineSeries(this);break;case QAbstractSeries::SeriesType::SeriesTypeScatter:
        series =newQScatterSeries(this);break;default:break;}

    m_chart->addSeries(series);
    series->setName(seriesName);
    series->attachAxis(m_xAxis);
    series->attachAxis(m_yAxis);// 隐藏点标签
    series->setPointLabelsVisible(false);

    m_mapSeries.insert(seriesName,series);}voidChartDrawer::setSeriesStyle(QString seriesName, Qt::GlobalColor color,int width){if(m_mapSeries.find(seriesName).value()==nullptr){qDebug()<<QStringLiteral("曲线不存在");return;}
    QPen splinePen;
    splinePen.setBrush(color);
    splinePen.setColor(color);
    splinePen.setWidth(width);
    m_mapSeries[seriesName]->setPen(splinePen);}voidChartDrawer::setAxisType(AxisType xType){
    m_xAxisType = xType;}inlineboolChartDrawer::compareX(QPointF a, QPointF b){return a.x()> b.x();}inlineboolChartDrawer::compareY(QPointF a, QPointF b){return a.y()> b.y();}voidChartDrawer::setAxisRange(double xMin,double xMax){
    m_xMin = xMin;
    m_xMax = xMax;}voidChartDrawer::setAxisRange(double slideDis){
    m_slideDis = slideDis;}voidChartDrawer::setAxisRange(){
    QVector<QPointF> olddata;foreach(QXYSeries *series, m_mapSeries){
        olddata << series->points();}
    QVector<QPointF> sortData = olddata;

    std::sort(sortData.begin(),sortData.end(),compareY);
    m_yMin = sortData.last().y();
    m_yMax = sortData.first().y();

    m_yAxis->setRange(m_yMin, m_yMax);if(m_xAxisType == AxisType_Static){}else{
        std::sort(sortData.begin(),sortData.end(),compareX);
        m_xMax = sortData.first().x();if(m_xAxisType == AxisType_Slide){
            m_xMin = m_xMax - m_slideDis;}elseif(m_xAxisType == AxisType_Dynamic){
            m_xMin = sortData.last().x();}}
    m_xAxis->setRange(m_xMin, m_xMax);//qDebug() << m_xMin << m_xMax << m_yMin << m_yMax;}doubleChartDrawer::getXAxisRange(){returndouble(m_xAxis->max()- m_xAxis->min());}doubleChartDrawer::getYAxisRange(){returndouble(m_yAxis->max()- m_yAxis->min());}voidChartDrawer::setAxisTitle(QString xTitle, QString yTitle){
    m_xAxis->setTitleText(xTitle);
    m_yAxis->setTitleText(yTitle);}voidChartDrawer::setGridVisible(bool isShow){int count =double(m_xAxis->max()- m_xAxis->min())/20;if(count < TICK_COUNT_MIN){
        count = TICK_COUNT_MIN;}elseif(count > TICK_COUNT_MAX){
        count = TICK_COUNT_MAX;}
    m_xAxis->setGridLineVisible(isShow);
    m_xAxis->setTickCount(count);
    m_xAxis->setMinorTickCount(MINOR_TICK_COUNT);

    count =double(m_yAxis->max()- m_yAxis->min())/20;if(count < TICK_COUNT_MIN){
        count = TICK_COUNT_MIN;}elseif(count > TICK_COUNT_MAX){
        count = TICK_COUNT_MAX;}
    m_yAxis->setGridLineVisible(isShow);
    m_yAxis->setTickCount(count);
    m_yAxis->setMinorTickCount(MINOR_TICK_COUNT);}voidChartDrawer::setLegendVisible(bool isShow){
    m_chart->legend()->setVisible(isShow);/*m_chart->legend()->setLayoutDirection(Qt::LeftToRight);
    m_chart->legend()->setAlignment(Qt::AlignBottom);*/}voidChartDrawer::setOriginPointFs(QString seriesName, QList<QPointF> data){if(m_mapSeries.find(seriesName).value()==nullptr){qDebug()<<QStringLiteral("曲线不存在");return;}
    m_mapSeries[seriesName]->append(data);}voidChartDrawer::addPointF(QString seriesName, QPointF pointf){if(m_mapSeries.find(seriesName).value()==nullptr){qDebug()<<QStringLiteral("曲线不存在");return;}//qDebug() << pointf;
    QVector<QPointF> olddata = m_mapSeries[seriesName]->points();if(olddata.size()>0){double xdis =abs(olddata[olddata.size()-1].x()- pointf.x());double ydis =abs(olddata[olddata.size()-1].y()- pointf.y());//qDebug() << "x:" << xdis << "," << "y:" << ydis;if(xdis < UPDATE_DIS && ydis < UPDATE_DIS)return;}
    olddata.append(pointf);
    m_mapSeries[seriesName]->replace(olddata);setAxisRange();}voidChartDrawer::clearAllPointF(){foreach(QXYSeries *series, m_mapSeries){
        series->replace(QVector<QPointF>());}}voidChartDrawer::mousePressEvent(QMouseEvent *pEvent){if(pEvent->button()== Qt::MiddleButton){
        m_middleButtonPressed =true;
        m_oPrePos = pEvent->pos();this->setCursor(Qt::OpenHandCursor);}elseif(pEvent->button()== Qt::RightButton){setAxisRange();}QChartView::mousePressEvent(pEvent);}voidChartDrawer::mouseReleaseEvent(QMouseEvent *pEvent){if(pEvent->button()== Qt::MiddleButton){
        m_middleButtonPressed =false;this->setCursor(Qt::ArrowCursor);}QChartView::mouseReleaseEvent(pEvent);}voidChartDrawer::wheelEvent(QWheelEvent *pEvent){

    QPointF point = pEvent->position();double rVal = std::pow(0.999, pEvent->angleDelta().y());
    QPointF chartPoint = m_chart->mapToValue(point);//计算当前点到最小点和最大点的距离,x轴和y轴double oldLeftDis = chartPoint.x()- m_xAxis->min();double oldRightDis = m_xAxis->max()- chartPoint.x();double oldDownDis = chartPoint.y()- m_yAxis->min();double oldUpDis = m_yAxis->max()- chartPoint.y();//计算当前点到缩放后的最小点和最大点的距离,x轴和y轴double newLeftDis = oldLeftDis * rVal;double newRightDis = oldRightDis * rVal;double newDownDis = oldDownDis * rVal;double newUpDis = oldUpDis * rVal;//计算新的坐标最小点和最大点double newXMin = chartPoint.x()- newLeftDis;double newXMax = chartPoint.x()+ newRightDis;double newYMin = chartPoint.y()- newDownDis;double newYMax = chartPoint.y()+ newUpDis;//重新设置坐标轴的显示范围
    m_xAxis->setRange(newXMin, newXMax);
    m_yAxis->setRange(newYMin, newYMax);QChartView::wheelEvent(pEvent);}voidChartDrawer::mouseMoveEvent(QMouseEvent *pEvent){
    QPoint point = pEvent->pos();if(m_middleButtonPressed){
     QPoint oDeltaPos = point - m_oPrePos;
     m_chart->scroll(-oDeltaPos.x(), oDeltaPos.y());
     m_oPrePos = point;}
    m_xLine->setLine(point.x(),0,point.x(),this->height());
    m_yLine->setLine(0,point.y(),this->width(),point.y());
    QPointF chartPoint = m_chart->mapToValue(point);
    m_txtPos->setPlainText(QString("%1,%2").arg(QString::number(chartPoint.x(),'f',3),QString::number(chartPoint.y(),'f',3)));
    m_txtPos->setPos(point.x(), point.y());QChartView::mouseMoveEvent(pEvent);}voidChartDrawer::enterEvent(QEnterEvent *pEvent){
    m_txtPos->setVisible(true);
    m_xLine->setVisible(true);
    m_yLine->setVisible(true);QChartView::leaveEvent(pEvent);}voidChartDrawer::leaveEvent(QEvent *pEvent){
    m_txtPos->setVisible(false);
    m_xLine->setVisible(false);
    m_yLine->setVisible(false);QChartView::leaveEvent(pEvent);}

控件类的使用

具体使用代码如下
1、初始化类对象,并加入界面布局中

    m_chartDrawer =newChartDrawer(this);
    vLayout->addWidget(m_chartDrawer);
    
    m_chartDrawer->setAxisTitle("时间/(s)","路程/(m)");
    m_chartDrawer->setGridVisible(true);
    m_chartDrawer->setLegendVisible(false);//    m_chartDrawer->setAxisType(ChartDrawer::AxisType::AxisType_Slide);//m_chartDrawer->setAxisRange(0,10);
    
    m_chartDrawer->addSeries(QAbstractSeries::SeriesTypeLine,"line0");
    m_chartDrawer->setSeriesStyle("line0", Qt::red,3);
    m_chartDrawer->setOriginPointFs("line0",QList<QPointF>());
    
    m_chartDrawer->addSeries(QAbstractSeries::SeriesTypeSpline,"line1");
    m_chartDrawer->setSeriesStyle("line1", Qt::green,3);
    m_chartDrawer->setOriginPointFs("line1",QList<QPointF>());

2、添加点到图表控件中
我这边定义了定时器,每隔1s交换的向两个曲线内添加一个点

voidMainWindow::timerEvent(QTimerEvent *event){//qDebug() << "aa";
    m_time +=1;srand(QTime(0,0,0).secsTo(QTime::currentTime()));double  m_distance =QRandomGenerator::global()->bounded(0,20);if(m_preLine =="line0"){
        m_chartDrawer->addPointF("line1",QPointF(m_time,m_distance));
        m_preLine ="line1";}else{
        m_chartDrawer->addPointF("line0",QPointF(m_time,m_distance));
        m_preLine ="line0";}}

3、从控件中移除所有点

m_chartDrawer->clearAllPointF();

如果还是看不懂、建议直接下载源代码

源码链接:https://download.csdn.net/download/xiaohuihuihuige/87264001

有帮助的话请点个赞吧。关注我,获取更多自定义控件

标签: qt 交互 ui

本文转载自: https://blog.csdn.net/xiaohuihuihuige/article/details/128265056
版权归原作者 xiaohuihuihuige 所有, 如有侵权,请联系我们删除。

“【[Qt]基于QChartView开发的图表显示控件,支持实时显示,动态更新,支持鼠标交互等操作】”的评论:

还没有评论