QT6.4 使用各种图表

本文介绍如何用QT6.4如何建立图表效果图,并给出源代码 及 演示exe。

在网上找了几个demo来试了一下,要么不能编译,要么有各种bug,要么制作很粗糙。于是我自己重新开发代码,并尽量简洁易懂好用。下面代码在Windows10 X64下编译运行。

欢迎学习交流开发。

效果图如下,演示exe在  QT6.4图表demo,可以快速学习使用-桌面系统文档类资源-CSDN文库

 

 

#ifndef CHARTWIDGET_H
#define CHARTWIDGET_H

#include <QWidget>
#include <QTimer>
#include <QChartView>
#include <QtCharts>
#include <QPieSeries>
#include <QPieSlice>
#include <QValueAxis>
#include <QLineSeries>
#include <QtCharts/QChartView>

QT_BEGIN_NAMESPACE
namespace Ui { class ChartWidget; }
QT_END_NAMESPACE
class DealThread;

class ChartWidget : public QWidget
{
    Q_OBJECT

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

    void createpieSewies();
    void createBarChart();
    void createAreaChart();
    void createLineChart();
    void createScatterChart();

private:
    // 用于模拟生成实时数据的定时器
    QTimer* mTimer;

    // 图表对象
    QChart* mChart;

    // 横纵坐标轴对象
    QValueAxis *mAxisX, *mAxisY;

    // 曲线图对象
    QLineSeries* mLineSeries;

    // 横纵坐标最大显示范围
    const int AXIS_MAX_X = 40, AXIS_MAX_Y = 12;

    // 用来记录数据点数
    int mPointCount = 0;

private:
    QPieSeries* mPieSeries;
    QChart*     mPieChart;
    QChartView* mPieChartView;

    QPieSeries* mPieSeries2;
    QChartView* mPieChartView2;

private:
    QBarSet*    mBarSet[5];
    QBarSeries* mSeries;
    QChart*     mBarChart;
    QBarCategoryAxis* mAxis;
    QChartView* mBarChartView;

    QChartView* mAreaChartView;
    QAreaSeries* mAreaSeries;
    QLineSeries* mUpperSeries, *mLowerSeries;
    QChartView* mLineChartView;
    QChartView* mScatterChartView;

    QVector<QLineSeries*> mLineSeriesVec;
    QVector<QScatterSeries*> mAcatterSeriesVec;
private:


private slots:
    void slotBtnClear();
    void slotBtnStartAndStop();
    void slotTimeout();
    void keyPressEvent(QKeyEvent *event);
    void closeEvent(QCloseEvent *event);

private:
    Ui::ChartWidget *ui;
};
#endif
#include "ChartWidget.h"
#include "DealThread.h"
#include "ui_ChartWidget.h"

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

    // 创建定时器
    mTimer = new QTimer(this);
    mTimer->setSingleShot(false);
    QObject::connect(mTimer, SIGNAL(timeout()), this, SLOT(slotTimeout()));

    QObject::connect(ui->btnClear, SIGNAL(clicked(bool)), this, SLOT(slotBtnClear()));
    QObject::connect(ui->btnStartAndStop, SIGNAL(clicked(bool)), this, SLOT(slotBtnStartAndStop()));

    // 创建横纵坐标轴并设置显示范围
    mAxisX = new QValueAxis();
    mAxisY = new QValueAxis();
    mAxisX->setTitleText("X-时间");
    mAxisY->setTitleText("Y-数值");
    mAxisX->setMin(0);
    mAxisX->setMax(AXIS_MAX_X);
    mAxisY->setMin(0);
    mAxisY->setMax(AXIS_MAX_Y);

    mLineSeries = new QLineSeries();                            // 创建曲线绘制画布
    mLineSeries->setPointsVisible(true);                        // 设置数据点可见
    mLineSeries->setName("动态数字连续曲线");                   // 设置图例名称

    mChart = new QChart();                                      // 创建图表对象
    mChart->addAxis(mAxisX, Qt::AlignBottom);                   // 将X轴添加到图表上
    mChart->addAxis(mAxisY, Qt::AlignLeft);                     // 将Y轴添加到图表上
    mChart->addSeries(mLineSeries);                             // 将曲线画布添加到图表上
    mChart->setAnimationOptions(QChart::SeriesAnimations);      // 启用动画模式,能使曲线绘制显示过渡的更平滑
    mChart->setAnimationDuration(400);                          // 动画持续时间间隔,要小于新增节点的时间 (否则导致现有节点变动位置为新位置)
    mChart->setBackgroundPen(QPen(QColor(33,88,155)));
    mChart->setBackgroundBrush(QBrush(QColor(0xF7F8CC)));

    mLineSeries->attachAxis(mAxisX);                            // 曲线对象关联上X轴,此步骤必须在mChart->addSeries之后
    mLineSeries->attachAxis(mAxisY);                            // 曲线对象关联上Y轴,此步骤必须在mChart->addSeries之后

    ui->widgetView->setChart(mChart);                           // 将图表对象设置到widgetView上进行显示
    ui->widgetView->setRenderHint(QPainter::Antialiasing);      // 启用抗锯齿效果

    createpieSewies();
    createBarChart();
    createAreaChart();
    createLineChart();
    createScatterChart();

    slotBtnStartAndStop();// 初始就点击开始计时器

ChartWidget::~ChartWidget()
{
    mPieChart->removeAllSeries();
    ui->hLayout2->removeWidget(mPieChartView);
    mPieSeries->deleteLater();
    mPieChart->deleteLater();
    mPieChartView->deleteLater();
    mPieSeries2->deleteLater();
    mPieChartView2->deleteLater();

    for(int i=0;i<5;i++)
        mSeries->remove(mBarSet[i]);
    mBarChart->removeAllSeries();
    ui->hLayout2->removeWidget(mBarChartView);
    for(int i=0;i<5;i++)
        mBarSet[i]->deleteLater();
    mSeries->deleteLater();
    mBarChart->deleteLater();
    mAxis->deleteLater();
    mBarChartView->deleteLater();

    mAreaChartView->deleteLater();
    mAreaSeries->deleteLater();
    mUpperSeries->deleteLater();
    mLowerSeries->deleteLater();
    mLineChartView->deleteLater();
    mScatterChartView->deleteLater();
    foreach (QLineSeries* m , mLineSeriesVec)
        m->deleteLater();
    foreach (QScatterSeries* m , mAcatterSeriesVec)
        m->deleteLater();

    delete ui;
    delete mTimer;
    delete mAxisX;
    delete mAxisY;
    delete mLineSeries;
    delete mChart;
    delete mThread;
}

// 创建饼状图
void ChartWidget::createpieSewies()
{
    // 饼状图
    mPieSeries = new QPieSeries();
    // 中间圆与大圆的比例,可以没有中间圆
    mPieSeries->setHoleSize(0.3);
    // 扇形及数据 0
    QPieSlice* pieSlice0 = mPieSeries->append("学者",25);//扇形占整个圆的百分比
    pieSlice0->setLabelVisible(); // 设置标签可见,缺省不可见
    pieSlice0->setColor(QColor(255,0,0,255)); // 启用主题前设置无效
    pieSlice0->setLabelColor(QColor(0x4cb9cf));
    pieSlice0->setBorderColor(QColor(0x4cb9cf));
    // 扇形及数据 1
    QPieSlice* pieSlice1 = mPieSeries->append("民工",30);
    pieSlice1->setLabelVisible(); // 设置标签可见,缺省不可见
    pieSlice1->setColor(QColor(0x53b666)); // 启用主题前设置无效
    pieSlice1->setLabelColor(QColor(0x53b666));
    pieSlice1->setBorderColor(QColor(0x53b666));
    // 扇形及数据 2
    QPieSlice* pieSlice2 = mPieSeries->append("白领",45);
    pieSlice2->setLabelVisible(); // 设置标签可见,缺省不可见
    pieSlice2->setColor(QColor(0x2f89cf)); // 启用主题前设置无效
    pieSlice2->setLabelColor(QColor(0x2f89cf));
    pieSlice2->setBorderColor(QColor(0x2f89cf));

    // 图表视图
    mPieChart = new QChart();
    mPieChart->setTitle("人员分布");
    mPieChart->addSeries(mPieSeries);
    mPieChart->setAnimationOptions(QChart::SeriesAnimations);
    mPieChart->legend()->setAlignment(Qt::AlignBottom);
    mPieChart->legend()->setBackgroundVisible(false);
//    mPieChart->legend()->setFont(QFont("黑体", 8)) ; // 图例字体
//    mPieChart->setTitleBrush(QColor(0x808396));
//    mPieChart->legend()->setLabelColor(QColor(0x808396));
    mPieChart->setTheme(QChart::ChartThemeBlueCerulean);
    pieSlice0->setColor(QColor(255,0,0,255)); // 启用主题前设置无效
    pieSlice1->setColor(QColor(97,81,233,255)); // 启用主题前设置无效
    pieSlice2->setColor(QColor(0,255,0,255)); // 启用主题前设置无效

    mPieChartView = new QChartView(mPieChart);
    mPieChartView->setRenderHint(QPainter::Antialiasing);
    mPieChartView->setRenderHint(QPainter::NonCosmeticBrushPatterns);

    ui->hLayout2->addWidget(mPieChartView);


    {
    //Creating donutchart
    mPieSeries2=new QPieSeries();
    mPieSeries2->setHoleSize(0.0);//圆孔大小
    QPieSlice *slice0 = mPieSeries2->append("学者 10%",10);
    slice0->setColor(QColor(97,81,233,255)); // 启用主题前设置无效
    //slice0->setLabelVisible(); // 设置标签可见,缺省不可见
        QPieSlice *slice1=mPieSeries2->append("躺平 15%",15); // 单个切片
        slice1->setExploded(); // 使该切片突出
        slice1->setLabelVisible(); // 显示切片的标签
        slice1->setColor(QColor(255,0,0,255)); // 启用主题前设置无效
    QPieSlice *slice2 = mPieSeries2->append("白领 30%",30);
    slice2->setLabelVisible(); // 设置标签可见,缺省不可见
    QPieSlice *slice3 = mPieSeries2->append("民工 35%", 40); // 以圆心为原点,以y轴为起始轴,圆环的每一小部分按照编程顺序顺时针排列。
    slice3->setColor(QColor(0,200,0,255)); // 启用主题前设置无效
    slice3->setLabelVisible(); // 设置标签可见,缺省不可见

    mPieChartView2=new QChartView();
    mPieChartView2->setRenderHint(QPainter::Antialiasing); // 启用抗锯齿
    mPieChartView2->chart()->setTitle("人员分布");
    mPieChartView2->chart()->addSeries(mPieSeries2);
    mPieChartView2->chart()->legend()->setAlignment(Qt::AlignBottom); // 图例放在底部
    mPieChartView2->chart()->setTheme(QChart::ChartThemeBlueIcy); // 主题颜色设置为天然色
    //chartView->chart()->legend()->setFont(QFont("Arial",7)); // 图例字体宋体7号字
    slice0->setColor(QColor(97,81,233,255)); // 启用主题前设置无效
    slice1->setColor(QColor(255,0,0,255)); // 启用主题前设置无效
    slice3->setColor(QColor(0,200,0,255)); // 启用主题前设置无效

    ui->hLayout2->addWidget(mPieChartView2);
    }
}

// 创建柱状图
void ChartWidget::createBarChart()
{
    mBarSet[0] = new QBarSet("产量");
    mBarSet[1] = new QBarSet("废料");
    mBarSet[2] = new QBarSet("销量");
    mBarSet[3] = new QBarSet("利润");
    mBarSet[4] = new QBarSet("产能");

    *mBarSet[0] << 2 << 12 << 3 << 4 << 7 << 5;     // 产量 6个月份的值
    *mBarSet[1] << 6 << 3 << 13 << 4 << 4 << 8;     // 废料 6个月份的值
    *mBarSet[2] << 3 << 4 << 8 << 14 << 3 << 4;     // 销量 6个月份的值
    *mBarSet[3] << 4 << 11 << 7 << 3 << 3 << 6;     // 利润 6个月份的值
    *mBarSet[4] << 8 << 8 << 6 << 12 << 4 << 9;     // 产能 6个月份的值

    mSeries = new QBarSeries();
    for(int i=0;i<5;i++)
    mSeries->append(mBarSet[i]);

    mBarChart = new QChart();
    mBarChart->addSeries(mSeries);
    mBarChart->setTitle("工厂经营状态图表");
    mBarChart->setAnimationOptions(QChart::SeriesAnimations);
    mBarChart->setTheme(QChart::ChartThemeBlueCerulean);

    QStringList categories;
    categories << "一月" << "二月" << "三月" << "四月" << "五月" << "六月";
    mAxis = new QBarCategoryAxis();
    mAxis->append(categories);
    mBarChart->createDefaultAxes();         // 创建默认的左侧的坐标轴(根据 QBarSet 设置的值)
    mBarChart->setAxisX(mAxis, mSeries);    // 设置坐标轴

    mBarChart->legend()->setVisible(true);  // 设置图例为显示状态
    mBarChart->legend()->setAlignment(Qt::AlignBottom); // 设置图例的显示位置在底部

    mBarChartView = new QChartView(mBarChart);
    mBarChartView->setRenderHint(QPainter::Antialiasing);

    ui->hLayout2->addWidget(mBarChartView);
}

// 创建面积图
void ChartWidget::createAreaChart()
{
    // 创建折线图系列对象,一块面积由上下两条折线合围
    mUpperSeries = new QLineSeries();
    mLowerSeries = new QLineSeries();

    *mUpperSeries << QPointF(1, 5) << QPointF(3, 7) << QPointF(7, 6) << QPointF(9, 7)
                 << QPointF(12,6) << QPointF(16,7) << QPointF(18,5);
    *mLowerSeries << QPointF(1, 3) << QPointF(3, 4) << QPointF(7, 3) << QPointF(8, 2)
                 << QPointF(12,3) << QPointF(16,4) << QPointF(18,3);
    //mLowerSeries->append(8, 6 + rand() % 6); // 也可以这样添加数据

    // 创建面积对象
    mAreaSeries = new QAreaSeries(mUpperSeries, mLowerSeries); // 一块面积由上下两条折线合围
    mAreaSeries->setName("稻田面积");
    QPen pen(0x059605);
    pen.setWidth(3);
    mAreaSeries->setPen(pen);
    // 设置边线和面积内部颜色
    QLinearGradient gradient(QPointF(0, 0), QPointF(0, 1));
    gradient.setColorAt(0.0, 0x3cc63c);
    gradient.setColorAt(1.0, 0x26f626);
    gradient.setCoordinateMode(QGradient::ObjectBoundingMode);
    mAreaSeries->setBrush(gradient);

    mAreaChartView = new QChartView();
    mAreaChartView->setRenderHint(QPainter::Antialiasing);
    // 创建QChart对象
    QChart *chart = mAreaChartView->chart();
    chart->addSeries(mAreaSeries);
    chart->setTitle("面积图");
    chart->createDefaultAxes();
    chart->axes(Qt::Horizontal).first()->setRange(0, 20);// 自定义坐标范围
    chart->axes(Qt::Vertical).first()->setRange(0, 10);
    //chart->createDefaultAxes();// 根据数据 创建默认坐标轴
    chart->setTheme(QChart::ChartThemeBlueCerulean);

    ui->hLayout3->addWidget(mAreaChartView);
}

// 创建折线图
void ChartWidget::createLineChart()
{
    mLineChartView = new QChartView();
    mLineChartView->setRenderHint(QPainter::Antialiasing);

    // 创建QChart对象
    QChart *chart = mLineChartView->chart();
    chart->setTitle( "折线图");// 设置标题
    chart->setTheme(QChart::ChartThemeBlueCerulean);

    // 添加图表值
    for(int i = 0; i < 2; i++) // 几条折线
    {
        // 创建折线图系列对象
        QLineSeries* series = new QLineSeries(chart);
        mLineSeriesVec.push_back(series);
        series->setName(!i?"产量":"质量");
        for(int k = 0; k < 6; k++)
            series->append(k, k * (i+1) + rand() % 6);
        chart->addSeries(series);// 将series添加到QChart对象中
    }
    chart->createDefaultAxes();// 根据数据 创建默认坐标轴

    ui->hLayout3->addWidget(mLineChartView);
}

// 创建散点图
void ChartWidget::createScatterChart()
{
    mScatterChartView = new QChartView();
    mScatterChartView->setRenderHint(QPainter::Antialiasing);

    // 创建QChart对象
    QChart *chart = mScatterChartView->chart();
    chart->setTitle( "散点图");// 设置标题
    chart->setTheme(QChart::ChartThemeBlueCerulean);

    // 添加图表值
    for(int i = 0; i < 2; i++) // 几条散点线
    {
        // 创建曲线图系列对象
        QScatterSeries* series = new QScatterSeries(chart);
        mAcatterSeriesVec.push_back(series);
        series->setName(!i?"苹果":"香蕉");
        if(i)series->setMarkerShape(QScatterSeries::MarkerShape::MarkerShapeStar);
        if(i)series->setColor(Qt::green);
        series->setBorderColor(Qt::transparent);
        series->setPen(QColor(Qt::transparent));

        for(int k = 0; k < 6; k++)
            series->append(k , k * i * 4 + rand() % 8);
        chart->addSeries(series);// 将series添加到QChart对象中
    }
    chart->createDefaultAxes();// 根据数据 创建默认坐标轴

    ui->hLayout3->addWidget(mScatterChartView);
}

void ChartWidget::slotBtnClear()
{
    mLineSeries->clear();
    mChart->axisX()->setMin(0);
    mChart->axisX()->setMax(AXIS_MAX_X);
    mPointCount = 0;

    //给子线程发信号和参数
    emit sengMsgToThread("hello to you");
}

void ChartWidget::slotBtnStartAndStop()
{
    if(mTimer->isActive())
    {
        mTimer->stop();
        ui->btnStartAndStop->setText("启动500ms定时器");
    }else
    {
        mTimer->start(500);
        ui->btnStartAndStop->setText("停止500ms定时器");
    }
}

void ChartWidget::slotTimeout()
{
    //连续生成动态数据 基于上一个节点数值计算
    static int ap=0,lastY=AXIS_MAX_Y/2;
    int y = lastY+((rand()%2)?1:-1)*(rand()%3+1);
    while(y>AXIS_MAX_Y-2 || y<2)
    {
        y = lastY+((rand()%2)?1:-1)*(rand()%3+1);
    }
    lastY=y;
    // 增加节点 更新显示(随机生成AXIS_MAX_Y以内的一个数)
    mLineSeries->append(QPointF(mPointCount, y));
    if(mPointCount >= AXIS_MAX_X)
    {
        mChart->axisX()->setMin(mPointCount - AXIS_MAX_X);
        mChart->axisX()->setMax(mPointCount);             // 更新X轴范围
        if(mPointCount > AXIS_MAX_X) mLineSeries->remove(0);
    }
    mPointCount++;
}

void ChartWidget::keyPressEvent(QKeyEvent *event)
{
    switch (event->key())
    {
    case Qt::Key_Escape:  // 按下的为Esc键
        qApp->quit();
        break;
    default:
        QWidget::keyPressEvent(event);
    }
}

void ChartWidget::closeEvent(QCloseEvent *event)
{
    event->accept();
}


 ChartWidget.ui  上的布局代码

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>ChartWidget</class>
 <widget class="QWidget" name="ChartWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>802</width>
    <height>758</height>
   </rect>
  </property>
  <property name="sizePolicy">
   <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
    <horstretch>0</horstretch>
    <verstretch>0</verstretch>
   </sizepolicy>
  </property>
  <property name="maximumSize">
   <size>
    <width>16777215</width>
    <height>16777215</height>
   </size>
  </property>
  <property name="windowTitle">
   <string>Charts</string>
  </property>
  <widget class="QWidget" name="verticalLayoutWidget">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>801</width>
     <height>741</height>
    </rect>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <property name="spacing">
     <number>0</number>
    </property>
    <property name="leftMargin">
     <number>6</number>
    </property>
    <property name="topMargin">
     <number>6</number>
    </property>
    <property name="rightMargin">
     <number>6</number>
    </property>
    <property name="bottomMargin">
     <number>6</number>
    </property>
    <item>
     <layout class="QHBoxLayout" name="hLayout0">
      <item>
       <widget class="QPushButton" name="btnClear">
        <property name="minimumSize">
         <size>
          <width>0</width>
          <height>30</height>
         </size>
        </property>
        <property name="text">
         <string>清空曲线</string>
        </property>
       </widget>
      </item>
      <item>
       <widget class="QPushButton" name="btnStartAndStop">
        <property name="minimumSize">
         <size>
          <width>0</width>
          <height>30</height>
         </size>
        </property>
        <property name="text">
         <string>启动500ms定时器</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
    <item>
     <layout class="QVBoxLayout" name="vLayout1">
      <item>
       <widget class="QChartView" name="widgetView" native="true"/>
      </item>
     </layout>
    </item>
    <item>
     <layout class="QHBoxLayout" name="hLayout2"/>
    </item>
    <item>
     <layout class="QHBoxLayout" name="hLayout3"/>
    </item>
   </layout>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>QChartView</class>
   <extends>QWidget</extends>
   <header location="global">qchartview.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections/>
</ui>

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值