Qt图表操作(QCustomPlot 与 QtCharts的介绍与使用)

news2024/11/26 22:48:21

一、QCustomPlot简介

  QCustomPlot是QT下一个方便易用的绘图工具,该绘图库专注于制作美观,出版品质的2D图表,图表和图表,以及为实时可视化应用程序提供高性能。它可以导出为各种格式,如矢量化的PDF文件和光栅化图像,如PNG,JPG和BMP。

官网:https://www.qcustomplot.com

下载:
在这里插入图片描述
    压缩包中有QCustomPlot的官方使用示例:plot-examples和核心文件: qcuamplesstomplot.h、qcustomplot.cpp,使用方法是通过添加现有文件将 qcustomplot.h、qcustomplot.cpp加入工程,并在pro文件中加入printsupport,放置widget并提升为QCustomPlot。
    外网网速不好,也可以通过csdn下载:https://download.csdn.net/download/linyibin_123/87388205

二、QtCharts简介

    Qt Charts是Qt自带的组件库,其中包含折线、曲线、饼图、棒图、散点图、雷达图等各种常用的图表。它的核心是 QChartView(显示图表)和QChart(管理数据),QChartView是一个能够显示图表的widget,是用来显示数据,而QChart类用来管理图表的数据序列(series)、图例(legends)和坐标轴(axes)。

三、QCustomPlot 与 QCharts的对比

1.性能:

    1)QCustomPlot是一个比较完善的框架,其框架和缓存化的处理使其处理性能大幅度提升,支持十万以上的数据量。
    2)QtCharts只是一个半成品,不论是否有bug,QtCharts在两千个点以内是可以使用的,超过两千个点就存在刷新卡顿的问题。

2.功能:

    QChart可绘制的图标种类比QCustomPlot多。

3.使用:

    QChar无需配置,是Qt自带的,QCustomPlot需要配置两个源文件:qcustomplot.h和qcustomplot.cpp。

四、QCustomPlot的使用

    官网的示例绘制的图表都相对复杂,以下demo封装一些常用的图表:柱状图、实时曲线图、饼状图。

1.界面效果

在这里插入图片描述
在这里插入图片描述

2.核心代码

ctcumtomplot.h

#ifndef CTCUMTOMPLOT_H
#define CTCUMTOMPLOT_H

#include <QObject>
#include <QMouseEvent>
#include "qcustomplot.h"
#include <QTimer>
#include "commondef.h"
#include "custombars.h"

class CtCumtomPlot : public QObject
{
    Q_OBJECT
public:
    explicit CtCumtomPlot();
    ~CtCumtomPlot();

    static CtCumtomPlot& getInstance();

    //曲线
    void CreateRealCurve(QCustomPlot *pCustomPlot);
    void setCurve(GRAPH_CURVE_T graphPara);

    //柱状图
    void CreateHistogram(QCustomPlot *pCustomPlot, GRAPH_HISTOGRAM_T graphPara);

public slots:
    void mouseMove(QMouseEvent *e);

private:
    //曲线
    QCustomPlot* m_pCurveCP;
    QCPItemTracer* m_pCurveT;
    QCPItemText* m_pCurveTL;

    //柱状图
    QCustomPlot* m_pHistogramCP;
};

#endif // CTCUMTOMPLOT_H

ctcumtomplot.cpp

#include "ctcumtomplot.h"
#include <QTime>

CtCumtomPlot::CtCumtomPlot()
{
}

CtCumtomPlot::~CtCumtomPlot()
{
    if(m_pCurveT)
        delete m_pCurveT;

    if(m_pCurveTL)
        delete m_pCurveTL;

    if(m_pCurveCP)
        delete m_pCurveCP;
}

CtCumtomPlot &CtCumtomPlot::getInstance()
{
    static CtCumtomPlot s_obj;
    return s_obj;
}

/**********************
*实时曲线
***********************/
void CtCumtomPlot::CreateRealCurve(QCustomPlot *pCustomPlot)
{
    m_pCurveCP = pCustomPlot;

    //设置布局
    pCustomPlot->plotLayout()->insertRow(0);
    pCustomPlot->plotLayout()->insertColumn(0);
    pCustomPlot->axisRect()->setAutoMargins(QCP::msBottom | QCP::msRight);
    pCustomPlot->plotLayout()->setRowStretchFactor(0, 0.1);
    pCustomPlot->plotLayout()->setColumnStretchFactor(0, 0.1);

    //设置图形标注
    pCustomPlot->legend->setVisible(true);
    pCustomPlot->legend->setFont(QFont("Helvetica", 9));
    pCustomPlot->legend->setTextColor(0x00ff00);
    pCustomPlot->legend->setFillOrder(QCPLayoutGrid::foColumnsFirst); //横向画图
    pCustomPlot->legend->setBorderPen(Qt::NoPen);//设置边框
    pCustomPlot->legend->setIconSize(50, 20);
    pCustomPlot->legend->setBrush(QBrush(Qt::transparent));//设置背景透明

    //设置背景
    pCustomPlot->setBackground(QBrush(QColor(128, 138, 135)));


    //设置坐标轴颜色\画笔\末端样式
    pCustomPlot->xAxis->setBasePen(QPen(QColor("#191970"), 2));     // 轴线画笔
    pCustomPlot->xAxis->setSubTickPen(QPen(QColor("#191970"), 1));  // 轴刻度的画笔
    pCustomPlot->xAxis->setSubTickPen(QPen(QColor("#191970"), 1));  // 轴子刻度线的画笔
    pCustomPlot->xAxis->setTickLabelColor(QColor("#191970"));       // 坐标轴上字体

    pCustomPlot->yAxis->setBasePen(QPen(QColor("#191970"), 2));     // 轴线画笔
    pCustomPlot->yAxis->setSubTickPen(QPen(QColor("#191970"), 1));  // 轴刻度的画笔
    pCustomPlot->yAxis->setSubTickPen(QPen(QColor("#191970"), 1));  // 轴子刻度线的画笔
    pCustomPlot->yAxis->setTickLabelColor(QColor("#191970"));       // 坐标轴上字体

    pCustomPlot->xAxis->setUpperEnding(QCPLineEnding::esFlatArrow);
    pCustomPlot->yAxis->setUpperEnding(QCPLineEnding::esFlatArrow);

    //添加一条曲线
    m_pCurveCP->addGraph();
    //设置右上角图形标注名称
    m_pCurveCP->graph(0)->setName(QString::fromLocal8Bit("Network Speed"));
    //设置画笔颜色
    m_pCurveCP->graph(0)->setPen(QPen(Qt::green, 2));

    //设置坐标轴时间显示
    QSharedPointer<QCPAxisTickerTime> timeTick(new QCPAxisTickerTime);
    timeTick->setTimeFormat("%h:%m:%s");
    m_pCurveCP->xAxis->setTicker(timeTick);

    //设置坐标轴描述
    m_pCurveCP->xAxis->setLabelFont(QFont("Microsoft YaHei", 10));
    m_pCurveCP->yAxis->setLabelFont(QFont("Microsoft YaHei", 10));
    m_pCurveCP->xAxis->setLabelColor(QColor("#191970"));
    m_pCurveCP->yAxis->setLabelColor(QColor("#191970"));
    m_pCurveCP->xAxis->setLabel("Time");
    m_pCurveCP->yAxis->setLabel("Value");

    //显示子刻度
    m_pCurveCP->xAxis->setSubTicks(true);
    m_pCurveCP->yAxis->setSubTicks(true);

    //设置基本坐标轴(左侧Y轴和下方X轴)可拖动、可缩放、曲线可选、legend可选、设置伸缩比例,使所有图例可见
    m_pCurveCP->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes |
                                   QCP::iSelectLegend | QCP::iSelectPlottables);

    //设置游标
    m_pCurveT = new QCPItemTracer(m_pCurveCP);
    m_pCurveT->setPen(QPen(Qt::red));//圆圈轮廓颜色
    m_pCurveT->setBrush(QBrush(Qt::red));//圆圈圈内颜色
    m_pCurveT->setStyle(QCPItemTracer::tsCircle);//圆圈
    m_pCurveT->setSize(5);//设置大小

    //游标说明
    m_pCurveTL = new QCPItemText(m_pCurveCP);
    m_pCurveTL->setLayer("overlay");//设置图层为overlay(频繁刷新需要)
    m_pCurveTL->setPen(QPen(Qt::black));//设置游标说明颜色
    m_pCurveTL->setPositionAlignment(Qt::AlignLeft | Qt::AlignTop);//左上
    m_pCurveTL->position->setParentAnchor(m_pCurveT->position);//将游标说明固定在游标上,实现自动跟随

    connect(m_pCurveCP, SIGNAL(mouseMove(QMouseEvent*)), this, SLOT(mouseMove(QMouseEvent*)));

    //使用上下轴 左右轴范围同步
    //connect(m_pCurveCP->xAxis, SIGNAL(rangeChanged(QCPRange)), m_pCurveCP->xAxis2, SLOT(setRange(QCPRange)));
    //connect(m_pCurveCP->yAxis, SIGNAL(rangeChanged(QCPRange)), m_pCurveCP->yAxis2, SLOT(setRange(QCPRange)));
}

void CtCumtomPlot::setCurve(GRAPH_CURVE_T graphPara)
{
    if(m_pCurveCP)
    {
        //设置数据
        m_pCurveCP->graph(0)->addData(graphPara.X, graphPara.Y);

        //删除10秒之前的数据
        m_pCurveCP->graph(0)->removeDataBefore(static_cast<int>(graphPara.X - 10));
        m_pCurveCP->yAxis->setRange(0, 6000);

        //设置Y轴有7个坐标
        m_pCurveCP->yAxis->ticker()->setTickCount(7);
        m_pCurveCP->graph(0)->rescaleKeyAxis();

        //设置横坐标范围
        m_pCurveCP->xAxis->setRange(graphPara.X, 10, Qt::AlignRight);//void QCPAxis::setRange (double position, double size, Qt::AlignmentFlag alignment )

        //重绘
        m_pCurveCP->replot();
    }
}

void CtCumtomPlot::mouseMove(QMouseEvent *e)
{
    //鼠标坐标转化为CustomPlot内部坐标
    double x = m_pCurveCP->xAxis->pixelToCoord(e->pos().x());

    //将游标和该曲线图层连接
    m_pCurveT->setGraph(m_pCurveCP->graph(0));

    //将游标横坐标设置成刚获得的横坐标数据x
    m_pCurveT->setGraphKey(x);

    //游标的纵坐标可以通过曲线数据线性插值自动获得
    m_pCurveT->setInterpolating(true);

    //使得刚设置游标的横纵坐标位置生效
    m_pCurveT->updatePosition();

    //更新游标说明的内容
    double xValue = m_pCurveT->position->key();
    double yValue = m_pCurveT->position->value();

    //x坐标转时间,游标显示
    QTime time1(0, 0, 0, 0);
    QTime newTime = time1.addMSecs(static_cast<int>(xValue*1000));
    m_pCurveTL->setText(QString("x = %1, y = %2").arg(newTime.toString(QString::fromLatin1("hh:mm:ss:zzz"))).arg(yValue));

    //重绘
    m_pCurveCP->replot();
}

/**********************
*柱状图
***********************/
void CtCumtomPlot::CreateHistogram(QCustomPlot *pCustomPlot, GRAPH_HISTOGRAM_T graphPara)
{
    m_pHistogramCP = pCustomPlot;

    //使用xAxis、yAxis作为柱状图的x轴、y轴
    QCPAxis *xAxis = m_pHistogramCP->xAxis;
    QCPAxis *yAxis = m_pHistogramCP->yAxis;
    CustomBars *pCusbars = new CustomBars(xAxis, yAxis);

    pCusbars->setName("Cusbars");
    pCusbars->setPen(QPen(QColor(0, 0, 0).lighter(150))); //设置柱状图的边框颜色
    pCusbars->setBrush(QColor(61, 133, 198)); //设置柱状图背景颜色

    QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);

    textTicker->addTicks(graphPara.VecX, graphPara.VecXLabels);
    xAxis->setTicker(textTicker); //设置为文字轴
    xAxis->setTickLabelRotation(50); //轴刻度文字旋转50度
    xAxis->setSubTicks(true); //显示子刻度
    xAxis->setTickLength(0, 4); //轴内外刻度的长度分别是0,4
    xAxis->setRange(0, 13); //设置x轴范围
    xAxis->setLabel("X");
    xAxis->setUpperEnding(QCPLineEnding::esSpikeArrow); //设置轴顶端箭头

    yAxis->setRange(0, 13); //设置y轴范围
    yAxis->setPadding(35); //轴的内边距
    yAxis->setLabel("y");
    yAxis->setUpperEnding(QCPLineEnding::esSpikeArrow);

    pCusbars->setData(graphPara.VecX, graphPara.VecY);
}

注意:removeDataBefore已经不被支持,需要在qcustomplot.h和qcustomplot.cpp中添加

custombars.h

#ifndef CUSTOMBARS_H
#define CUSTOMBARS_H

#include "qcustomplot.h"

class CustomBars : public QCPBars
{
public:
    explicit CustomBars(QCPAxis *keyAxis, QCPAxis *valueAxis);

    //设置文字对齐方式
    void setTextAlignment(Qt::Alignment alignment);
    Qt::Alignment textAligment() const;

    //设置文字与柱状图的间距
    void setSpacing(double spacing);
    double spacing() const;

    //设置字体
    void setFont(const QFont &font);
    QFont font() const;

protected:
    Qt::Alignment m_textAlign;
    double m_spacing;
    QFont m_font;

    virtual void draw(QCPPainter *painter) Q_DECL_OVERRIDE;
};

#endif // CUSTOMBARS_H

custombars.cpp

#include "custombars.h"

CustomBars::CustomBars(QCPAxis *keyAxis, QCPAxis *valueAxis)
    : QCPBars (keyAxis, valueAxis),
      m_textAlign(Qt::AlignCenter),
      m_spacing(6),
      m_font(QFont(QLatin1String("sans serif"), 12))
{
}

void CustomBars::setTextAlignment(Qt::Alignment alignment)
{
    m_textAlign = alignment;
}

Qt::Alignment CustomBars::textAligment() const
{
    return m_textAlign;
}

void CustomBars::setSpacing(double spacing)
{
    m_spacing = spacing;
}

double CustomBars::spacing() const
{
    return m_spacing;
}

void CustomBars::setFont(const QFont &font)
{
    m_font = font;
}

QFont CustomBars::font() const
{
    return m_font;
}

void CustomBars::draw(QCPPainter *painter)
{
    if (!mKeyAxis || !mValueAxis)
    {
        qDebug() << Q_FUNC_INFO << "invalid key or value axis";
        return;
    }

    if (mDataContainer->isEmpty())
        return;

    QCPBarsDataContainer::const_iterator visibleBegin, visibleEnd;
    getVisibleDataBounds(visibleBegin, visibleEnd);

    QList<QCPDataRange> selectedSegments, unselectedSegments, allSegments;
    getDataSegments(selectedSegments, unselectedSegments);
    allSegments << unselectedSegments << selectedSegments;
    for (int i=0; i<allSegments.size(); ++i)
    {
        bool isSelectedSegment = i >= unselectedSegments.size();
        QCPBarsDataContainer::const_iterator begin = visibleBegin;
        QCPBarsDataContainer::const_iterator end = visibleEnd;
        mDataContainer->limitIteratorsToDataRange(begin, end, allSegments.at(i));
        if (begin == end)
            continue;

        for (QCPBarsDataContainer::const_iterator it=begin; it!=end; ++it)
        {
            //draw bar
            if (isSelectedSegment && mSelectionDecorator)
            {
                mSelectionDecorator->applyBrush(painter);
                mSelectionDecorator->applyPen(painter);
            }
            else
            {
                painter->setBrush(mBrush);
                painter->setPen(mPen);
            }

            applyDefaultAntialiasingHint(painter);
            QRectF barRect = getBarRect(it->key, it->value);
            painter->drawPolygon(barRect);

            //计算文字的位置
            painter->setFont(m_font); //设置字体
            QString text = QString::number(it->value, 'g', 2); //取得当前value轴的值,保留两位精度
            QRectF textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip | m_textAlign, text); //计算文字所占用的大小

            if (mKeyAxis.data()->orientation() == Qt::Horizontal) //当key轴为水平轴的时候
            {
                if (mKeyAxis.data()->axisType() == QCPAxis::atTop) //上轴,移动文字到柱状图下面
                    textRect.moveTopLeft(barRect.bottomLeft() + QPointF(0, m_spacing));
                else                                                   //下轴,移动文字到柱状图上面
                    textRect.moveBottomLeft(barRect.topLeft() - QPointF(0, m_spacing));

                textRect.setWidth(barRect.width());
                painter->drawText(textRect, Qt::TextDontClip | m_textAlign, text);
            }
            else //当key轴为竖直轴的时候
            {
                if (mKeyAxis.data()->axisType() == QCPAxis::atLeft)   //左轴,移动文字到柱状图右边
                    textRect.moveTopLeft(barRect.topRight() + QPointF(m_spacing, 0));
                else                                                  //右轴,移动文字到柱状图左边
                    textRect.moveTopRight(barRect.topLeft() - QPointF(m_spacing, 0));

                textRect.setHeight(barRect.height());
                painter->drawText(textRect, Qt::TextDontClip | m_textAlign, text);
            }
        }
    }
}

commondef.h

#ifndef COMMONDEFS_H
#define COMMONDEFS_H

#include <QObject>
#include <QDebug>
#include <QMetaType>
#include <QVector>


#define  MY_DEBUG  qDebug() << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] "
#define  ACT_ENABLE(act, en)  if(act) { act->setEnabled(en);}
#define  SAFE_FREE(p) \
do { \
    if(p) \
    { \
        delete p; \
        p = NULL; \
    } \
} while(0)

typedef struct Graph_Curve_t
{
    double X;
    double Y;
}GRAPH_CURVE_T;

typedef struct Graph__t
{
    QVector<double> VecX;
    QVector<QString> VecXLabels;
    QVector<double> VecY;

}GRAPH_HISTOGRAM_T;

typedef struct Graph_Pie_t
{
    QVector<QString> VecLabels;
    QVector<double> VecValues;

}GRAPH_PIE_T;


#endif 

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "commondef.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    //曲线
    void initCurve();
    //柱状图
    void initHistogram();
    //QCustomPlot不能绘制饼状图

private slots:
    void on_pushButton_CurveStart_clicked();
    void on_pushButton_CurveStop_clicked();
    void on_showCurve();

private:
    Ui::MainWindow *ui;
    QTimer *m_pCurveTimer;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ctcumtomplot.h"
#include <QDateTime>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_pCurveTimer = new QTimer(this);
    connect(m_pCurveTimer, SIGNAL(timeout()),
            this, SLOT(on_showCurve()));

    //动态曲线
    initCurve();

    //柱状图
    initHistogram();
}

MainWindow::~MainWindow()
{
    delete ui;
}

/***********************
*动态曲线
************************/
void MainWindow::initCurve()
{
    CtCumtomPlot::getInstance().CreateRealCurve(ui->widget_Tab1);
}

void MainWindow::on_showCurve()
{
    //随机数种子
    //qsrand(QTime(0, 0, 0).secsTo(QTime::currentTime()));

    GRAPH_CURVE_T CurveParam;
    CurveParam.X = QTime::currentTime().hour()*60*60 + QTime::currentTime().minute()*60 + QTime::currentTime().second();
    //MY_DEBUG << "m_graphParam.X:" << m_graphParam.X;

    double tmp = static_cast<double>(rand() % (1000) + 2000);
    CurveParam.Y = static_cast<double>(rand() % (1000) + tmp);

    CtCumtomPlot::getInstance().setCurve(CurveParam);
}

void MainWindow::on_pushButton_CurveStart_clicked()
{
    m_pCurveTimer->start(1000);
}

void MainWindow::on_pushButton_CurveStop_clicked()
{
    m_pCurveTimer->stop();
}

/***********************
*柱状图
************************/
void MainWindow::initHistogram()
{
    //X轴
    GRAPH_HISTOGRAM_T HistogramParam;
    HistogramParam.VecX << 1 << 2 << 3 << 4 << 5 << 6 << 7 << 8 << 9 << 10 << 11 << 12;
    HistogramParam.VecXLabels << "Jan" << "Feb" << "Mar" << "Apr" << "May" <<
                              "Jun" << "Jul" << "Aug" << "Sep" << "Oct" <<
                              "Nov" << "Dec";
    //Y轴
    QTime randtime;
    randtime = QTime::currentTime();
    qsrand(randtime.msec()+randtime.second()*1000); //以当前时间ms为随机种子
    for(int i = 0; i < 12; i++)
    {
        int nVal = qrand() % 100;        //产生100以内的随机整数
        double dVal = double(nVal)/10;   //产生10以内的随机浮点数,精度为小数点后1位

        HistogramParam.VecY << dVal;
    }

    //创建柱状图
    CtCumtomPlot::getInstance().CreateHistogram(ui->widget_Tab2, HistogramParam);
}

3.demo工程下载:

下载地址: https://download.csdn.net/download/linyibin_123/87388205

五、QtCharts的使用

使用QtCharts封装饼状图:

1.界面

在这里插入图片描述

2.核心代码

注意:
1)pro中需要添加
QT += charts

2)界面处理:
在这里插入图片描述

ctchart.h

#ifndef CTCHART_H
#define CTCHART_H

#include <QObject>
#include <QChar>
#include <QtCharts/QChartView>
#include <QValueAxis>
#include <QValueAxis>
#include <QtCharts/QPieSeries>
#include <QtCharts/QPieSlice>
#include "commondef.h"

QT_CHARTS_USE_NAMESPACE

class ctChart : public QObject
{
    Q_OBJECT
public:
    explicit ctChart();
    ~ctChart();

    static ctChart& getInstance();

    void createPie(QChartView *pGraphView, GRAPH_PIE_T stPie);

private:
    QChart* m_pChart;
};

#endif // CTCHART_H

ctchart.cpp

#include "ctchart.h"

ctChart::ctChart()
{
}

ctChart::~ctChart()
{
}

ctChart &ctChart::getInstance()
{
    static ctChart s_obj;
    return s_obj;
}

void ctChart::createPie(QChartView *pGraphView, GRAPH_PIE_T stPie)
{
    QChart *pChart = new QChart();
    QPieSeries *pSeries = new QPieSeries();

    for(int i = 0; i < stPie.VecValues.size(); i++)
    {
        //饼状分区
        QPieSlice* pSlice = new QPieSlice(stPie.VecLabels.at(i), stPie.VecValues.at(i), this);
        pSlice->setLabelVisible(true);
        pSlice->setBrush(stPie.VecColor.at(i));

        //饼状分区加入series
        pSeries->append(pSlice);
    }
    pSeries->setLabelsVisible(true);

    //添加pSeries到QChart
    pChart->addSeries(pSeries);

    //设置显示时的动画效果
    pChart->setAnimationOptions(QChart::AllAnimations);
    pChart->setTitle("Pie Chart");

    //不显示图描述
    pChart->legend()->hide();

    pGraphView->setChart(pChart);

    pGraphView->setRenderHint(QPainter::Antialiasing);
}

commondef.h

#ifndef COMMONDEFS_H
#define COMMONDEFS_H

#include <QObject>
#include <QDebug>
#include <QMetaType>
#include <QVector>


#define  MY_DEBUG  qDebug() << "[" << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << "] "
#define  ACT_ENABLE(act, en)  if(act) { act->setEnabled(en);}
#define  SAFE_FREE(p) \
do { \
    if(p) \
    { \
        delete p; \
        p = NULL; \
    } \
} while(0)

typedef struct Graph_Curve_t
{
    double X;
    double Y;
    int nYMinRange;
    int nYMaxRange;
}GRAPH_CURVE_T;

typedef struct Graph_Histogram_t
{
    QVector<double> VecX;
    QVector<QString> VecXLabels;
    QVector<double> VecY;

}GRAPH_HISTOGRAM_T;

typedef struct Graph_Pie_t
{
    QVector<QString> VecLabels;
    QVector<double> VecValues;
    QVector<QColor> VecColor;

}GRAPH_PIE_T;


#endif 

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "ctchart.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void initPie();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDateTime>
#include <QTimer>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    initPie();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::initPie()
{
    GRAPH_PIE_T graphPie;
    graphPie.VecLabels.append("10% A");
    graphPie.VecLabels.append("20% B");
    graphPie.VecLabels.append("30% C");
    graphPie.VecLabels.append("40% D");

    graphPie.VecValues.append(10);
    graphPie.VecValues.append(20);
    graphPie.VecValues.append(30);
    graphPie.VecValues.append(40);

    graphPie.VecColor.append(QColor(0,0,255,255));
    graphPie.VecColor.append(QColor(0,255,0,255));
    graphPie.VecColor.append(QColor(0,255,255,0));
    graphPie.VecColor.append(QColor(0,255,0,0));

    ctChart::getInstance().createPie(ui->graphicsView_Pie, graphPie);
}

3.demo工程下载

https://download.csdn.net/download/linyibin_123/87388205

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/167108.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Task12 数据缘何而来数据格式

目录1 常见的格式1.1 Excel文件的格式1.2 Excel数据的格式1.3 基本知识2 Excel数据格式2.1 数据类型转换3 练习1 常见的格式 1.1 Excel文件的格式 Excel文件的常见格式&#xff1a;.xls和.xlsx 1.2 Excel数据的格式 Excel数据的存储不同格式&#xff1a;xlsx、csv、txt cs…

mysql快速生成100W条测试数据(8)全球各城市人口及经济增长速度并存入mysql数据库

这是之前的文章里面包含一些以前的一些操作流程可以进行参考学习 更加详细操作步骤在第一篇文章里面 mysql快速生成100W条测试数据&#xff08;1&#xff09;&#xff1a;游戏人物数据 mysql快速生成100W条测试数据&#xff08;2&#xff09;公司员工信息 mysql快速生成100W条测…

本地挂载网盘_Alist_RaiDrive_windows

目录 一、下载安装Alist 二、启动登录Alist 三、挂载网盘 四、挂载到本地 五、开机自启动 一、下载安装Alist 安装地址&#xff1a;https://github.com/alist-org/alist 二、启动登录Alist 1.打开alist.exe所在目录&#xff0c;输入cmd 2.利用cmd&#xff0c;输入alist …

[oeasy]python0051_ 转义_escape_字符_character_单引号_双引号_反引号_ 退格键

转义字符 回忆上次内容 上次研究的是进制转化10进制可以转化为其他形式 binocthex 其他进制也可以转化为10进制 int可以设置base来决定转为多少进制 回忆一下 我们为什么会有八进制&#xff1f;因为需要用八进制输出转义字符 \ooo 把(ooo)8进制对应的ascii字符输出 就如同 \…

QMAKE_POST_LINK QMAKE_PRE_LINK解释

命令解释 QMAKE_POST_LINK是在可执行程序链接后执行它的命令 QMAKE_PRE_LINK是在可执行程序链接前执行它的命令 注意C/C程序是先编译后链接 如果你需要一个编译前执行的命令可以使用 copy_files.files $$filelist copy_files.path $$OUT_PWD COPIES copy_files即使是编…

存储与数据库 | 字节青训营笔记

目录 一、存储系统 1、什么是存储系统 2、存储系统的特点 3、RAID技术 RAID出现的背景 RAID 0 RAID 1 RAID 01 二、数据库 1、难道数据库和存储系统不一样吗 2、数据库vs经典存储 三、主流产品剖析 1、单机存储 本地文件系统 key-value存储 2、分布式存储系统 …

【程序员陪你过大年】html+css+js 实现春节动态烟花特效及服务器部署

前言 不知不觉又到了年底&#xff0c;这一年是值得庆贺的一年&#xff0c;疫情过去&#xff0c;经济好转。我们急需在春节这个特殊的日志释放下自己的情绪。但是大部分地区都不让放炮&#xff0c;于是乎我为大家带来一套十分炫酷应景的春节烟花动画代码实现。效果如下图所示 :…

第10章 FreeRTOS

ESP32 FREERTOS 打印ESP32任务 menuconfig中&#xff0c;打开FreeRTOS的trace打印功能 menuconfig中&#xff0c;增加app_main主任务的栈大小 测试代码 ESP32最小工程 #include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h&q…

php sql注入

文章目录一、什么是sql注入二、sql注入处理1、使用内置函数2、使用pdo预处理语句三、安全注意事项一、什么是sql注入 在应用程序中&#xff0c;为了和用户交互&#xff0c;允许用户提交输入数据&#xff0c;假如应用程序并没有对用户输入数据进行处理&#xff0c;攻击者可以输…

linux开发工具

文章目录linux开发工具1.软件包管理器yum2.编辑器vim3.gcc4.make与makefile5.git6.gdb7.小程序进度条linux开发工具 1.软件包管理器yum yum等同于手机上的应用商店.yum自动解决软件之间的耦合问题 yum list 显示软件清单 yum install 下载 yum remove 删除 2.编辑器vim 其…

opencv开发之numpy使用

打开Spyder, 在IPython控制台中输入 import numpy as np 引入numpy库并使用numpy构造一个ndarray对象: np.zeros((2,4),np.uint8),该对象为一个二维数组 ,构造一个2行4列的二维数组(矩阵) ,并初始化所有元素为0,及指定数据类型为uint8 创建并初始化:数据可视化:取矩阵类型: typ…

基于YOLOv4的车辆检测 MATLAB实现

目录 摘要 研究背景 算法设计及实现过程 车辆目标数据集的构建 基于YOLOv4的目标检测 对YOLOv4模型进行改进 实验结果及分析 结论与展望 代码实现 摘要 针对车辆检测&#xff0c;本文提出了一种基于YOLOv4车辆检测算法。制作了一个多天侯、多时段、多场景的车辆目标数…

怎么拆分PDF文件,教你用最简单的方法

PDF文档拆分是一种很常见的需求。因为有时候文档页数过多&#xff0c;打开和阅读都不太方便&#xff0c;我们可以通过拆分把想要的部分提取出来。拆分PDF的时候可以借助一些工具更快更有效地达成目的&#xff0c;这里就给大家介绍几款比较受欢迎的处理工具&#xff0c;它们在辅…

Linux——系统管理篇

1、、Linux 中的进程和服务 计算机中、一个正在执行的程序或命令&#xff0c;叫进程&#xff08;process&#xff09;。 启动之后一直存在、常驻内存的进程&#xff0c;一般称为“服务”&#xff08;Service&#xff09; // 我更喜欢叫它守护进程 Daemon 比如windows的那一堆…

软件测试面试,如何自我介绍?

01 如何自我介绍 面试过程中一定要放慢语速&#xff0c;做到条理清晰。特别是做自我介绍时&#xff0c;可以适当多介绍自己会什么&#xff0c;有哪些重要经验。 例如&#xff1a; 面试官&#xff0c;上午/下午好。 我是XXX&#xff0c;今天来面试贵公司的软件测试工程师岗位&a…

利用QT 的 Graphics View 系统实现一个 简易的 Graph Editor

QT 中的 Graphics View 系统. 是一个相对成熟的渲染引擎的上层框架&#xff0c;通常也可以会叫做 Scene - View。 通常会有 QGraphicsView, QGraphicsScene, QGraphicsItem 这几个类构成。 view是视口(viewport)&#xff1b;scene是一个场景&#xff0c;负责容纳各种item&…

JS语言基础

目录 语法 关键字与保留字 变量 var关键字 let声明 暂时性死区 全局变量 for循环中的let声明 条件声明 const声明 语法 1. 区分大小写 无论是变量、函数名还是操作符&#xff0c;都区分大小写。 2. 标识符 所谓标识符&#xff0c;就是变量、函数、属性或函数参数的名…

centos7配置(nvidia+cuda+cudnn+anaconda+tensorflow)gpu开发环境

一、安装准备 1、查看nvidia显卡&#xff0c;我的是T4显卡 lspci | grep -i nvidia2、查看linux系统版本 uname -m && cat /etc/redhat-release3、安装依赖 yum install gcc kernel-devel kernel-headers二、安装nvidia驱动 1、禁用nouveau lsmod | grep nouveau…

Powershell渗透框架

文章目录Powershell基础Powershell简介什么是 Windows PowerShell为什么使用 Windows PowerShell如何启动 Windows PowerShellPowerShell和Cmd命令提示符的区别PowerShellcmd管理员运行 PowerShellWindows PowerShell ISE创建并运行脚本文本编辑器创建脚本集成脚本环境创建脚本…

第二章.线性回归以及非线性回归—特征缩放,交叉验证法,过拟合

第二章.线性回归以及非线性回归 2.9 特征缩放 1.数据归一化 1).作用&#xff1a; 把数据的取值范围处理为0-1或者-1-1 2).数据范围处理为0-1之间的方法&#xff1a; newValue(oldValue-min)/(max-min) 例如&#xff1a;数组:&#xff08;1,3,5&#xff09;,value1:(1-1)/(5-1)0…