Qt之QChart各个图表的简单使用(含源码+注释)

一、图表操作示例图

1.图表选择示例

下图演示了通过下拉列表框切换图表的操作。
在这里插入图片描述

2.动画选项操作

下图演示了动画选项中三种动画的效果。
在这里插入图片描述

3.图例选项操作

下图演示了图例选项中四种图例的显示位置。
在这里插入图片描述

4.其他选项操作

下图演示了图表添加防锯齿功能和标题的隐藏和显示。
在这里插入图片描述
提示:不会使用Qt设计师设计界面的小伙伴点击这里

二、QChart(个人理解)

  1. 使用前需要在pro文件中添加“QT +=charts”;
  2. 在头文件中添加了对应的QChart头文件还不够还需要使用对应的命名空间可通过宏定义或者using使用QChart的命名空间(详情请看代码);
  3. QChart的数据分装层次大概为 QChartView -> QChart -> Series -> Value,就是说view装chart,chart装series, series装对应类型的值,一些图表值中可能还会细分,只要记住这个顺序,一般都不会漏掉;
  4. 在开发过程中,发现QChart有时还是不那么灵活,在使用过程中就得考虑灵活性这些了。

三、部分源码讲解

ui中添加动态属性

本文在ui中设置了大量的动态属性,所有按钮都有对应的动态属性,ui中添加/移除动态属性操作如下。
在这里插入图片描述

按钮组的使用

本文使用了三个(动画组、图例组、其他)按钮组链接槽函数做操作;
在帮助中查看按钮组信号,发现其有“void buttonClicked(QAbstractButton *button)”信号,正好适用于本文,于是通过该信号与槽函数链接。按钮组链接槽函数的方法有多种,这里简述三种,如下:

  1. 定义参数为(QAbstractButton *button)的槽函数,通过connect手动链接信号槽(详情查看源码)
  2. 根据Qt槽函数标准定义槽函数,在构建时会自动链接,构建格式为:“on_Object Name_Signal”(Object Name:对象名, Signal:触发槽函数的信号,详情看源码)。

四、源码

(因为本文ui中包含动态属性,所以本文会留下ui代码,可复制粘贴到ui文件使用)

CChartTest.h

#ifndef CCHARTTEST_H
#define CCHARTTEST_H

#include <QMainWindow>
#include <QtCharts>

//! 使用QChart需要使用对应的命名空间
//! 使用方法有如下两种(更改宏定义判断条件即可更换调用方法)
#if true
QT_CHARTS_USE_NAMESPACE     // 定义好的宏定义使用命名空间
#else
using namespace QtCharts;   // 常规使用命名空间的方法
#endif

namespace Ui {
class CChartTest;
}

class CChartTest : public QMainWindow
{
    Q_OBJECT

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

    /**
     * @brief createPieChart 创建饼图指针
     * @return 返回饼图QChart指针
     */
    QChart *createPieChart();

    /**
     * @brief createAreaChart 创建区域图指针
     * @return 返回区域图QChart指针
     */
    QChart *createAreaChart();

    /**
     * @brief createLineChart 创建折线图指针
     * @return 返回折线图QChart指针
     */
    QChart *createLineChart();

    /**
     * @brief createSpLineChart 创建曲线图指针
     * @return 返回曲线图QChart指针
     */
    QChart *createSpLineChart();

    /**
     * @brief createBarChart 创建柱状图指针
     * @return 返回柱状图QChart指针
     */
    QChart *createBarChart();

    /**
     * @brief createScatterChart 创建散点图指针
     * @return 返回散点图QChart指针
     */
    QChart *createScatterChart();

    void setChartAttribute(QChart *chart, QString title);

private slots:
    /**
     * @brief on_comboBox_currentIndexChanged 图标类型下拉列表框索引改变槽函数
     * @param index 改变后的索引值
     */
    void on_comboBox_currentIndexChanged(int index);

    /**
     * @brief on_legendGroupButtonClicked 图例按钮组点击槽函数
     * @param button 所点击按钮
     */
    void on_legendGroupButtonClicked(QAbstractButton *button);

    /**
     * @brief on_animationGroup_buttonClicked 动画组按钮组点击槽函数
     * @param button 所点击按钮
     */
    void on_animationGroup_buttonClicked(QAbstractButton *button);

    /**
     * @brief on_otherGroup_buttonClicked 其他组按钮组点击槽函数
     * @param button 所点击按钮
     */
    void on_otherGroup_buttonClicked(QAbstractButton *button);

private:
    Ui::CChartTest      *ui;

    QChartView          *m_chartView;       // view对象(用于显示QChart图形)

    QVector<QChart *>   m_chartVector;      // 存储各个类型chart的容器
};

#endif // CCHARTTEST_H

CChartTest.cpp

#include "CChartTest.h"
#include "ui_CChartTest.h"

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

    // 创建view对象控件
    m_chartView = new QChartView();
    // 将view空间添加到ui中
    ui->horizontalLayout->addWidget(m_chartView);

    // 添加饼图
    m_chartVector.append(createPieChart());
    // 设置默认显示饼图
    m_chartView->setChart(m_chartVector.at(0));
    // 添加柱状图
    m_chartVector.append(createBarChart());
    // 添加面积图
    m_chartVector.append(createAreaChart());
    // 添加折线图
    m_chartVector.append(createLineChart());
    // 添加曲线图
    m_chartVector.append(createSpLineChart());
    // 添加散点图
    m_chartVector.append(createScatterChart());


    // 手动连接信号槽
    connect(ui->legendGroup, SIGNAL(buttonClicked(QAbstractButton *))
            , this, SLOT(on_legendGroupButtonClicked(QAbstractButton *)));

    ui->otherGroup->setExclusive(false);    // 设置其他选项组可复选
}

CChartTest::~CChartTest()
{
    // 逆向释放图表空间(保证构造顺序和析构顺序相反)
    for(int index = m_chartVector.size() - 1; index != -1; --index)
    {
        delete m_chartVector[index];
    }

    // 释放view
    delete m_chartView;

    // 释放ui
    delete ui;
}

QChart *CChartTest::createPieChart()
{
    // 创建QChart对象
    QChart *chart = new QChart();
    // 创建饼图系列对象
    QPieSeries *series = new QPieSeries(chart);
    // 遍历假数据容器将数据添加到series对象中

    qsrand(QDateTime::currentMSecsSinceEpoch() % 20000);

    // 添加图表值
    for(int index = 0; index != 5; ++index)
    {
        series->append(QString(65 + index), rand() % 100);
    }

    // 将series添加到QChart对象中
    chart->addSeries(series);

    // 设置通用属性
    setChartAttribute(chart, "饼图");
    // 返回QChart对象
    return chart;
}

QChart *CChartTest::createAreaChart()
{
    // 创建QChart对象
    QChart *chart = new QChart();

    // 添加图表值
    //! 创建区域图系列对象
    //! 区域图的系列对象
    QLineSeries *lowerSeries = nullptr;
    for(int count = 1; count != 3; ++count)
    {
        // 创建折线图系列对象
        QLineSeries *upperSeries = new QLineSeries(chart);
        for(int index = 1; index != 5; ++index)
        {
            upperSeries->append(index , index * count * 5 + rand() % 5);
        }
        // 将series添加到QChart对象中
        QAreaSeries *series = new QAreaSeries(upperSeries, lowerSeries);
        lowerSeries = upperSeries;
        chart->addSeries(series);
    }

    // 设置通用属性
    setChartAttribute(chart, "面积图");
    // 返回QChart对象
    return chart;
}

QChart *CChartTest::createLineChart()
{
    // 创建QChart对象
    QChart *chart = new QChart();

    // 添加图表值
    for(int count = 0; count != 3; ++count)
    {
        // 创建折线图系列对象
        QLineSeries *series = new QLineSeries(chart);
        for(int index = 0; index != 5; ++index)
        {
            series->append(index * count, index * count - rand() % 3);
        }
        // 将series添加到QChart对象中
        chart->addSeries(series);
    }

    // 设置通用属性
    setChartAttribute(chart, "折线图");
    // 返回QChart对象
    return chart;
}

QChart *CChartTest::createSpLineChart()
{
    // 创建QChart对象
    QChart *chart = new QChart();

    // 添加图表值
    for(int count = 0; count != 3; ++count)
    {
        // 创建曲线图系列对象
        QSplineSeries *series = new QSplineSeries(chart);
        for(int index = 0; index != 5; ++index)
        {
            series->append(index * count, index * count - rand() % 8);
        }
        // 将series添加到QChart对象中
        chart->addSeries(series);
    }

    // 设置通用属性
    setChartAttribute(chart, "曲线图");
    // 返回QChart对象
    return chart;
}

QChart *CChartTest::createBarChart()
{
    // 创建QChart对象
    QChart *chart = new QChart();
    // 创建饼图系列对象
    QBarSeries *series = new QBarSeries(chart);

    qsrand(QDateTime::currentMSecsSinceEpoch() % 20000);

    // 添加图表值
    for(int count = 0; count != 3; ++count)
    {
        // 创建曲线图系列对象
        QBarSet *set = new QBarSet(QString(65 + count));
        for(int index = 0; index != 5; ++index)
        {
            set->append(rand() % 100);
        }
        series->append(set);
    }

    // 将series添加到QChart对象中
    chart->addSeries(series);

    // 设置通用属性
    setChartAttribute(chart, "柱状图");
    // 返回QChart对象
    return chart;
}

QChart *CChartTest::createScatterChart()
{
    // 创建QChart对象
    QChart *chart = new QChart();

    // 添加图表值
    for(int count = 0; count != 3; ++count)
    {
        // 创建曲线图系列对象
        QScatterSeries *series = new QScatterSeries(chart);
        for(int index = 0; index != 5; ++index)
        {
            series->append(index , index * count * 5 + rand() % 5);
        }
        // 将series添加到QChart对象中
        chart->addSeries(series);
    }

    // 设置通用属性
    setChartAttribute(chart, "散点图");
    // 返回QChart对象
    return chart;
}

void CChartTest::setChartAttribute(QChart *chart, QString title)
{
    // 创建默认坐标轴
    chart->createDefaultAxes();
    // 设置标题
    chart->setTitle(title);
    // 设置data,在设置标题时使用
    chart->setData(Qt::UserRole, title);
}

void CChartTest::on_comboBox_currentIndexChanged(int index)
{
    // 拿到chart容器中相同索引位置的QChart对象,并将其设置到view对象上
    QChart *chart = m_chartVector[index];
    m_chartView->setChart(chart);
}

void CChartTest::on_legendGroupButtonClicked(QAbstractButton *button)
{
    // 拿到发送信号的单选按钮
    QRadioButton *btn = dynamic_cast<QRadioButton *>(button);
    // 遍历图表容器,将legend的aign属性设为当前按钮对应的属性状态
    foreach(QChart *chart, m_chartVector)
    {
        //! 拿到当前单选按钮的属性值并强转为Qt::Alignment类型
        //!
        Qt::Alignment align = static_cast<Qt::Alignment>(btn->property("LegendValue").toUInt());
        // 将类型值设置到当前图表上
        chart->legend()->setAlignment(align);
    }
}

void CChartTest::on_animationGroup_buttonClicked(QAbstractButton *button)
{
    // 拿到发送信号的单选按钮
    QRadioButton *btn = dynamic_cast<QRadioButton *>(button);
    // 遍历图表容器,将chart的动画设为当前按钮对应的属性状态
    foreach(QChart *chart, m_chartVector)
    {
        //! 拿到当前单选按钮的属性值并强转为Qt::AnimationOption
        //! 其属性值为对应动画的int值,可通过帮助查看具体值
        QChart::AnimationOption animation = static_cast<QChart::AnimationOption>(btn->property("AnimationValue").toUInt());
        // 将类型值设置到当前图表上
        chart->setAnimationOptions(animation);
    }

}

void CChartTest::on_otherGroup_buttonClicked(QAbstractButton *button)
{
    // 拿到发送信号的复选按钮
    QCheckBox *btn = dynamic_cast<QCheckBox *>(button);
    // 判断所点击按钮的勾选状态
    bool checked = btn->isChecked();
    // 通过按钮动态属性判断按钮操作
    switch(btn->property("btnType").toInt())
    {
    case 0:
    {
        // 设置view的防锯齿,其还包含其他防锯齿选项,可查看帮助了解
        m_chartView->setRenderHint(QPainter::Antialiasing, checked);
        break;
    }
    case 1:
    {
        foreach(QChart *chart, m_chartVector)
        {
            // 通过三目运算符判断标题是否获取data中的值
            QString title = checked? chart->data(Qt::UserRole).toString(): "";
            // 设置标题
            chart->setTitle(title);
        }
        break;
    }
    default:
        break;
    }

}

CChartTest.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>CChartTest</class>
 <widget class="QMainWindow" name="CChartTest">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>625</width>
    <height>475</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>CChartTest</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QHBoxLayout" name="horizontalLayout">
    <item>
     <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1,1,1">
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout2">
        <item>
         <widget class="QLabel" name="label">
          <property name="text">
           <string>图表类型:</string>
          </property>
         </widget>
        </item>
        <item>
         <widget class="QComboBox" name="comboBox">
          <item>
           <property name="text">
            <string>饼图</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>柱状图</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>面积图</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>折线图</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>曲线图</string>
           </property>
          </item>
          <item>
           <property name="text">
            <string>散点图</string>
           </property>
          </item>
         </widget>
        </item>
       </layout>
      </item>
      <item>
       <widget class="QGroupBox" name="groupBox">
        <property name="title">
         <string>动画选项</string>
        </property>
        <layout class="QGridLayout" name="gridLayout">
         <item row="0" column="0">
          <widget class="QRadioButton" name="radioButton">
           <property name="text">
            <string>无动画</string>
           </property>
           <property name="checked">
            <bool>true</bool>
           </property>
           <property name="AnimationValue" stdset="0">
            <number>0</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">animationGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QRadioButton" name="radioButton_2">
           <property name="text">
            <string>栅格轴动画</string>
           </property>
           <property name="AnimationValue" stdset="0">
            <number>1</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">animationGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="1" column="0">
          <widget class="QRadioButton" name="radioButton_3">
           <property name="text">
            <string>系列动画</string>
           </property>
           <property name="AnimationValue" stdset="0">
            <number>2</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">animationGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="1" column="1">
          <widget class="QRadioButton" name="radioButton_4">
           <property name="text">
            <string>所有动画</string>
           </property>
           <property name="AnimationValue" stdset="0">
            <number>3</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">animationGroup</string>
           </attribute>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item>
       <widget class="QGroupBox" name="groupBox_2">
        <property name="title">
         <string>图例选项</string>
        </property>
        <layout class="QGridLayout" name="gridLayout_2">
         <item row="0" column="0">
          <widget class="QRadioButton" name="radioButton_9">
           <property name="text">
            <string>无图例</string>
           </property>
           <property name="LegendValue" stdset="0">
            <number>0</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">legendGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="0" column="1">
          <widget class="QRadioButton" name="radioButton_11">
           <property name="text">
            <string>图例靠上</string>
           </property>
           <property name="checked">
            <bool>true</bool>
           </property>
           <property name="LegendValue" stdset="0">
            <UInt>32</UInt>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">legendGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="1" column="0">
          <widget class="QRadioButton" name="radioButton_12">
           <property name="text">
            <string>图例靠左</string>
           </property>
           <property name="LegendValue" stdset="0">
            <number>1</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">legendGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="1" column="1">
          <widget class="QRadioButton" name="radioButton_10">
           <property name="text">
            <string>图例靠右</string>
           </property>
           <property name="LegendValue" stdset="0">
            <number>2</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">legendGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="1" column="2">
          <widget class="QRadioButton" name="radioButton_13">
           <property name="text">
            <string>图例靠下</string>
           </property>
           <property name="LegendValue" stdset="0">
            <number>64</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">legendGroup</string>
           </attribute>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
      <item>
       <widget class="QGroupBox" name="groupBox_3">
        <property name="title">
         <string>其他选项</string>
        </property>
        <layout class="QGridLayout" name="gridLayout_3">
         <item row="0" column="1">
          <widget class="QCheckBox" name="checkBox_2">
           <property name="text">
            <string>显示标题</string>
           </property>
           <property name="checked">
            <bool>true</bool>
           </property>
           <property name="btnType" stdset="0">
            <number>1</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">otherGroup</string>
           </attribute>
          </widget>
         </item>
         <item row="0" column="0">
          <widget class="QCheckBox" name="checkBox">
           <property name="text">
            <string>防锯齿</string>
           </property>
           <property name="btnType" stdset="0">
            <number>0</number>
           </property>
           <attribute name="buttonGroup">
            <string notr="true">otherGroup</string>
           </attribute>
          </widget>
         </item>
        </layout>
       </widget>
      </item>
     </layout>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>625</width>
     <height>23</height>
    </rect>
   </property>
  </widget>
  <widget class="QToolBar" name="mainToolBar">
   <attribute name="toolBarArea">
    <enum>TopToolBarArea</enum>
   </attribute>
   <attribute name="toolBarBreak">
    <bool>false</bool>
   </attribute>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
 <buttongroups>
  <buttongroup name="animationGroup"/>
  <buttongroup name="legendGroup"/>
  <buttongroup name="otherGroup"/>
 </buttongroups>
</ui>

main.cpp

#include "CChartTest.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    CChartTest w;
    w.show();

    return a.exec();
}

总结

本文功能不算完整,理论上说各个图表的选项独立,不是通用的更好(就是说每次点击按钮只改变当前图表的属性),有兴趣的伙伴可以优化此功能,其实除了本文的功能只是皮毛,QChart还有许多神奇操作,学无止境,就一起去发掘吧。
终于把这文章写完了,足足拖了我两周,最近实在是没时间,也太忙了,每天下了班根本不想敲代码,只想躺平,然后就拖到了现在😂。
最后给自己也给大家说“不做思想上的巨人行动上的矮子”,那就休息了,晚安😁。

相关文章

Qt之QtDataVisualization各三维图表的简单使用(含源码+注释)

友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 ^o^/)

注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除

  • 29
    点赞
  • 155
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 19
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lw向北.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值