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

这篇具有很好参考价值的文章主要介绍了【[Qt]基于QChartView开发的图表显示控件,支持实时显示,动态更新,支持鼠标交互等操作】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

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

先来看演示视频

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

控件类关键代码说明

十字线和显示坐标实现

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

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

在Cpp文件中初始化

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

    m_yLine = new QGraphicsLineItem();
    m_yLine->setPen(QPen(QColor( 100, 100, 100 )));
    m_yLine->setZValue(2);

    scene()->addItem(m_xLine);
    scene()->addItem(m_yLine);

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

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

void ChartDrawer::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);
}
void ChartDrawer::enterEvent(QEnterEvent *pEvent)
{
    m_txtPos->setVisible(true);
    m_xLine->setVisible(true);
    m_yLine->setVisible(true);
    QChartView::leaveEvent(pEvent);
}

void ChartDrawer::leaveEvent(QEvent *pEvent)
{
    m_txtPos->setVisible(false);
    m_xLine->setVisible(false);
    m_yLine->setVisible(false);
    QChartView::leaveEvent(pEvent);
}

其他实现请参考具体代码

控件类实现具体代码

ChartDrawer.h文件

#ifndef CHARTDRAWER_H
#define CHARTDRAWER_H

#include <QtCharts>
#include <QChartView>
#include <QWidget>
#include <QGraphicsLineItem>
#include <QLabel>
#include <QGraphicsTextItem>

#define UPDATE_DIS 0.001
#define MINOR_TICK_COUNT 10
#define TICK_COUNT_MIN 5
#define TICK_COUNT_MAX 20
#define TICK_DIS_DEFAULT 20
#define DEFAULT_X_MIN 0
#define DEFAULT_X_MAX 10
#define DEFAULT_Y_MIN 0
#define DEFAULT_Y_MAX 10

class ChartDrawer : public QChartView
{
    Q_OBJECT
public:
    explicit ChartDrawer(QWidget *parent = nullptr);
    ~ChartDrawer();

    enum AxisType{
        AxisType_Static = 0,
        AxisType_Slide,
        AxisType_Dynamic
    };

    QAbstractSeries::SeriesType getSeriesType();
    void addSeries(QAbstractSeries::SeriesType type = QAbstractSeries::SeriesTypeLine,QString seriesName = "");
    void setSeriesStyle(QString seriesName = "", Qt::GlobalColor color = Qt::red, int width = 2);
    void setAxisType(AxisType xType = AxisType_Dynamic);
    void setAxisRange(double xMin, double xMax);
    void setAxisRange(double slideDis);
    void setAxisRange();
    double getXAxisRange();
    double getYAxisRange();
    void setAxisTitle(QString xTitle, QString yTitle);
    void setGridVisible(bool isShow);
    void setLegendVisible(bool isShow);
    void setOriginPointFs(QString seriesName, QList<QPointF>);
    void addPointF(QString seriesName, QPointF);
    void clearAllPointF();
    static bool compareX(QPointF a, QPointF b);
    static bool compareY(QPointF a, QPointF b);


    virtual void mousePressEvent(QMouseEvent *pEvent) override;
    virtual void mouseReleaseEvent(QMouseEvent *pEvent) override;
    virtual void wheelEvent(QWheelEvent *pEvent) override;
    virtual void mouseMoveEvent(QMouseEvent *e) override;
    virtual void enterEvent(QEnterEvent *pEvent) override;
    virtual void leaveEvent(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 = new QChart();
    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 = new QGraphicsLineItem();
    m_xLine->setPen(QPen(QColor( 100, 100, 100 )));
    m_xLine->setZValue(2);

    m_yLine = new QGraphicsLineItem();
    m_yLine->setPen(QPen(QColor( 100, 100, 100 )));
    m_yLine->setZValue(2);

    scene()->addItem(m_xLine);
    scene()->addItem(m_yLine);

    m_txtPos = new QGraphicsTextItem();
    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;
}
void ChartDrawer::addSeries(QAbstractSeries::SeriesType type,QString seriesName)
{
    m_seriesType = type;
    QXYSeries *series;
    switch(type)
    {
    case QAbstractSeries::SeriesType::SeriesTypeLine:
        series = new QLineSeries(this);
        break;
    case QAbstractSeries::SeriesType::SeriesTypeSpline:
        series = new QSplineSeries(this);
        break;
    case QAbstractSeries::SeriesType::SeriesTypeScatter:
        series = new QScatterSeries(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);
}
void ChartDrawer::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);
}

void ChartDrawer::setAxisType(AxisType xType)
{
    m_xAxisType = xType;
}

inline bool ChartDrawer::compareX(QPointF a, QPointF b)
{
    return a.x() > b.x();
}
inline bool ChartDrawer::compareY(QPointF a, QPointF b)
{
    return a.y() > b.y();
}

void ChartDrawer::setAxisRange(double xMin, double xMax)
{
    m_xMin = xMin;
    m_xMax = xMax;
}
void ChartDrawer::setAxisRange(double slideDis)
{
    m_slideDis = slideDis;
}
void ChartDrawer::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;
        } else if(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;
}
double ChartDrawer::getXAxisRange()
{
    return double(m_xAxis->max() - m_xAxis->min());
}
double ChartDrawer::getYAxisRange()
{
    return double(m_yAxis->max() - m_yAxis->min());
}
void ChartDrawer::setAxisTitle(QString xTitle, QString yTitle)
{
    m_xAxis->setTitleText(xTitle);
    m_yAxis->setTitleText(yTitle);
}

void ChartDrawer::setGridVisible(bool isShow)
{
    int count = double(m_xAxis->max() - m_xAxis->min()) / 20;
    if(count < TICK_COUNT_MIN){
        count = TICK_COUNT_MIN;
    } else if(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;
    } else if(count > TICK_COUNT_MAX){
        count = TICK_COUNT_MAX;
    }
    m_yAxis->setGridLineVisible(isShow);
    m_yAxis->setTickCount(count);
    m_yAxis->setMinorTickCount(MINOR_TICK_COUNT);
}

void ChartDrawer::setLegendVisible(bool isShow)
{
    m_chart->legend()->setVisible(isShow);
    /*m_chart->legend()->setLayoutDirection(Qt::LeftToRight);
    m_chart->legend()->setAlignment(Qt::AlignBottom);*/
}
void ChartDrawer::setOriginPointFs(QString seriesName, QList<QPointF> data)
{
    if(m_mapSeries.find(seriesName).value() == nullptr){
        qDebug() << QStringLiteral("曲线不存在");
        return;
    }
    m_mapSeries[seriesName]->append(data);
}
void ChartDrawer::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();
}
void ChartDrawer::clearAllPointF()
{
    foreach(QXYSeries *series, m_mapSeries){
        series->replace(QVector<QPointF>());
    }
}
void ChartDrawer::mousePressEvent(QMouseEvent *pEvent)
{
    if (pEvent->button() == Qt::MiddleButton) {
        m_middleButtonPressed = true;
        m_oPrePos = pEvent->pos();
        this->setCursor(Qt::OpenHandCursor);
    } else if(pEvent->button() == Qt::RightButton) {
        setAxisRange();
    }
    QChartView::mousePressEvent(pEvent);
}
void ChartDrawer::mouseReleaseEvent(QMouseEvent *pEvent)
{
    if (pEvent->button() == Qt::MiddleButton) {
        m_middleButtonPressed = false;
        this->setCursor(Qt::ArrowCursor);
    }
    QChartView::mouseReleaseEvent(pEvent);
}
void ChartDrawer::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);
}
void ChartDrawer::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);
}
void ChartDrawer::enterEvent(QEnterEvent *pEvent)
{
    m_txtPos->setVisible(true);
    m_xLine->setVisible(true);
    m_yLine->setVisible(true);
    QChartView::leaveEvent(pEvent);
}

void ChartDrawer::leaveEvent(QEvent *pEvent)
{
    m_txtPos->setVisible(false);
    m_xLine->setVisible(false);
    m_yLine->setVisible(false);
    QChartView::leaveEvent(pEvent);
}

控件类的使用

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

	m_chartDrawer = new ChartDrawer(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交换的向两个曲线内添加一个点

void MainWindow::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

有帮助的话请点个赞吧。关注我,获取更多自定义控件文章来源地址https://www.toymoban.com/news/detail-422016.html

到了这里,关于【[Qt]基于QChartView开发的图表显示控件,支持实时显示,动态更新,支持鼠标交互等操作】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Qt编写监控实时显示和取流回放工具(回放支持切换进度)

    现在各个监控大厂做的设备,基本上都会支持通过rtsp直接取流显示,而且做的比较好的还支持通过rtsp回放取流,基本上都会约定一个字符串的规则,每个厂家都是不一样的规则,比如回放对应的rtsp地址还要带上时间范围,回放肯定要指定一个开始时间和结束时间。这里需要

    2024年02月10日
    浏览(50)
  • Qt/C++编写监控实时显示和取流回放工具(回放支持切换进度)

    现在各个监控大厂做的设备,基本上都会支持通过rtsp直接取流显示,而且做的比较好的还支持通过rtsp回放取流,基本上都会约定一个字符串的规则,每个厂家都是不一样的规则,比如回放对应的rtsp地址还要带上时间范围,回放肯定要指定一个开始时间和结束时间。这里需要

    2024年02月11日
    浏览(46)
  • Qt6使用QChartView类与鼠标事件实现波形的缩放、平移、坐标轴单轴缩放与鼠标悬停显示点的数据

            说在前面,本人也是近段时间刚开始学习Qt,实现上述功能的方法可能并不是最优,写此篇文章也是记录下学习的过程,也与大家分享一下。(在此先描述,后面会附上代码)(前面说的会比较基础)         首先,要使用QChartView类得现在.pro文件中加入:(得确保

    2024年02月09日
    浏览(39)
  • 基于Qt5的图像交互控件开发(C++实现)

    博主近期看到海康VM、halcon以及visionpro视觉软件都包含一个图像智能交互控件,然后近期根据其中的技术原理,也基于Qt5仿照开发了一个类似的功能,包含矩形、旋转矩形、任意多边形、圆、圆环、扇环,直线卡尺以及圆卡尺等常用控件,图像智能交互是在计算机视觉领域中

    2024年02月05日
    浏览(59)
  • Qt音视频开发44-本地摄像头推流(支持分辨率/帧率等设置/实时性极高)

    本地摄像头推流和本地桌面推流类似,无非就是采集的设备源头换成了本地摄像头设备而不是桌面,其他代码完全一样。采集本地摄像头实时视频要注意的是如果设置分辨率和帧率,一定要是设备本身就支持的,如果不支持那就歇菜,比如设备本身最大分辨率到1280x720,你主

    2024年02月05日
    浏览(47)
  • Qt音视频开发43-采集屏幕桌面并推流(支持分辨率/矩形区域/帧率等设置/实时性极高)

    采集电脑屏幕桌面并推流一般是用来做共享桌面、远程协助、投屏之类的应用,最简单入门的做法可能会采用开个定时器或者线程抓图,将整个屏幕截图下来,然后将图片传出去,这种方式很简单但是性能要低不少,一般采用ffmpeg来做桌面推流的居多,毕竟如果不采用代码直

    2024年02月03日
    浏览(49)
  • Qt QScrollArea显示控件,并且调节控件大小

    实现效果: (1)首先要理解 QScrollArea控件出现滚动条的方式,具体参考(11条消息) QT的自动滚动区QScrollArea的用法,图文详解_暴躁的野生猿的博客-CSDN博客_qscrollarea  在scrollArea的子控件设置mininumSize就是显示滚动条关键; (2)在 QScrollArea 添加自定义控件(这里以添加QPushB

    2024年02月11日
    浏览(38)
  • 海康威视摄像头二次开发_云台控制_视频画面实时预览(基于Qt实现)

    需求:需要在公司的产品里集成海康威视摄像头的SDK,用于控制海康威视的摄像头。 拍照抓图、视频录制、云台控制、视频实时预览等等功能。 开发环境: windows-X64(系统) + Qt5.12.6(Qt版本) + MSVC2017_X64(使用的编译器) 海康威视提供了 设备网络SDK ,设备网络SDK是基于设备私有网

    2024年02月13日
    浏览(60)
  • Qt QWidget 抗锯齿圆角窗口的一个实现方案(支持子控件)

    由于 QWidget::setMask 接口设置圆角不支持抗锯齿,所以通常会使用透明窗口加圆角背景,但圆角背景不能满足对子控件的裁剪,子控件与圆角区域重叠的部分还是能显示出来。当然对于大多数窗口,留出足够的边距也是可以接受。 对一些特殊场景,比如QComboBox的列表框,UI设计

    2023年04月24日
    浏览(62)
  • Qt for python QChartView鼠标滚动放大缩小

    最近使用Qt for python 做了一个图表,有个需求是用鼠标中轮,根据中轮的滚动来放大缩小显示的曲线,我这边用Qml实现的QChart图表, 当然QWidget的相应方法也会提到,都是一样的,相对于qml实现这个功能是真麻烦,得使用C++才能实现,而我又是使用的python,所以难度更大,正好

    2024年02月09日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包