QT Charts绘图-柱状图、折线图的绘画

QT Charts绘图-柱状图、折线图的绘画

​ 图表的类型由数据序列决定,除了折线图,QT charts还提供了柱状图、饼图、百分比图等常见图表。本程序主要目的时演示柱状图的绘制方法,以此深入了解QT Charts的基本用法。

程序实现的功能

​ 在运行界面的左上方 “初始化数据“ 按钮实现了随机生成若干个学生的数学、语文、英语分数。平均分是自动计算的,左下方是根据分数统计的结果,右方是图表的页面。当我们修改学生数据时,themodel会发出itemChanged()信号,相应的on_itemChanged()槽函数自动跟新图表,和统计结果。运行界面如下:

在这里插入图片描述

界面分析

​ 窗口左上方是一个QTableView组件,使用Model/View结构提供数据编辑功能。左下角是一个QTreeWidget组件,用于显示统计数据结果。窗口右方是一个QTabWidget组件,用于显示柱状图。图表的显示用一个QgraphicsView组件升级为QChartsView。

mainwindow.h的实现

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include    <QStandardItemModel>
#include    <QItemSelectionModel>
#include <QtCharts>

#define fixedColumnCount   5    //数据模型的列数
#define iniDataRowCount    10   //学生个数

#define colNoName       0   //姓名的列编号
#define colNoMath       1   //数学的列编号
#define colNoChinese    2   //语文的列编号
#define colNoEnglish    3   //英语的列编号
#define colNoAverage    4   //平均分的列编号

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT
private:
    QStandardItemModel  *theModel;//数据模型

    void    iniData();//初始化数据
    void    surveyData();//统计数据

    void    iniBarChart(); //柱状图初始化
    void    buildBarChart();//构建柱状图

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

private slots:
    void on_actGenData_triggered();	//初始化数据
    void on_actTongJi_triggered();	//统计结果
    //当数据发生变化时 更新图表
    void on_itemChanged(QStandardItem *item);
    void on_btnBuildBarChart_clicked();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

​ mainwindow.cpp的实现

#include "mainwindow.h"
#include "ui_mainwindow.h"

void MainWindow::iniData()
{
    //数据初始化
    QStringList     headerList;
    headerList<<"姓名"<<"数学"<<"语文"<<"英语"<<"平均分";
    theModel->setHorizontalHeaderLabels(headerList); //设置表头文字

    qsrand(QTime::currentTime().second());//随机数种子
    for (int i=0;i<theModel->rowCount();i++)
    {
        QString studName=QString::asprintf("学生%2d",i+1);
        QStandardItem*  aItem=new QStandardItem(studName);//创建item
        aItem->setTextAlignment(Qt::AlignHCenter);
        theModel->setItem(i,colNoName,aItem); //i行,学生列,设置item

        qreal avgScore=0;
        for (int j=colNoMath;j<=colNoEnglish;j++) //数学,语文,英语
        { //不包含最后一列
            qreal score=50.0+(qrand() % 50);//随机数
            avgScore+=score;

            aItem=new QStandardItem(QString::asprintf("%.0f",score));//创建 item
            aItem->setTextAlignment(Qt::AlignHCenter);
            theModel->setItem(i,j,aItem); //为模型的某个行列位置设置Item
        }
        aItem=new QStandardItem(QString::asprintf("%.1f",avgScore/3));//创建平均分item
        aItem->setTextAlignment(Qt::AlignHCenter);
        aItem->setFlags(aItem->flags() & (!Qt::ItemIsEditable));//平均分不允许编辑
        theModel->setItem(i,colNoAverage,aItem); //平均分
    }
}

void MainWindow::surveyData()
{
    //数据统计
    int cnt50,cnt60,cnt70,cnt80,cnt90;

    qreal   sumV,minV,maxV;
    qreal   val;
    QTreeWidgetItem *item; //节点

    int i,j;
    for(i=colNoMath;i<=colNoAverage;i++)
    {
        sumV=0;
        cnt50=0;
        cnt60=0;
        cnt70=0;
        cnt80=0;
        cnt90=0;

        for(j=0;j<theModel->rowCount();j++)
        {
            val=theModel->item(j,i)->text().toDouble();

            if (j==0)
            {
                minV=val;
                maxV=val;
            }
            if (val<minV)
                minV=val;
            if (val>maxV)
                maxV=val;
            //
            sumV+=val;

            if (val<60)
                cnt50++;
            else if ((val>=60) && (val<70))
                cnt60++;
            else if ((val>=70) && (val<80))
                cnt70++;
            else if ((val>=80) && (val<90))
                cnt80++;
            else
                cnt90++;
        }
        //
        item=ui->treeWidget->topLevelItem(0); //<60
        item->setText(i,QString::number(cnt50));
        item->setTextAlignment(i,Qt::AlignHCenter);

        item=ui->treeWidget->topLevelItem(1); //60
        item->setText(i,QString::number(cnt60));
        item->setTextAlignment(i,Qt::AlignHCenter);

        item=ui->treeWidget->topLevelItem(2); //70
        item->setText(i,QString::number(cnt70));
        item->setTextAlignment(i,Qt::AlignHCenter);

        item=ui->treeWidget->topLevelItem(3); //80
        item->setText(i,QString::number(cnt80));
        item->setTextAlignment(i,Qt::AlignHCenter);

        item=ui->treeWidget->topLevelItem(4); //90
        item->setText(i,QString::number(cnt90));
        item->setTextAlignment(i,Qt::AlignHCenter);

        item=ui->treeWidget->topLevelItem(5); //average
        item->setText(i,QString::number(sumV/theModel->rowCount()));
        item->setTextAlignment(i,Qt::AlignHCenter);

        item=ui->treeWidget->topLevelItem(6); //max
        item->setText(i,QString::number(maxV));
        item->setTextAlignment(i,Qt::AlignHCenter);

        item=ui->treeWidget->topLevelItem(7); //min
        item->setText(i,QString::number(minV));
        item->setTextAlignment(i,Qt::AlignHCenter);
    }
}

void MainWindow::iniBarChart()
{
    //柱状图初始化
    QChart*chart=new QChart();
    chart->setTitle("BarChar 演示");
    chart->setAnimationOptions(QChart::SeriesAnimations);
    ui->chartViewBar->setChart(chart);
    ui->chartViewBar->setRenderHint(QPainter::Antialiasing);
}

void MainWindow::buildBarChart()
{
    //构造柱状图
    QChart *chart =ui->chartViewBar->chart(); //获取ChartView关联的chart
    chart->removeAllSeries(); //删除所有序列

    chart->removeAxis(chart->axisX()); //删除坐标轴
    chart->removeAxis(chart->axisY()); //删除坐标轴

    //创建三个QBarSet数据集,从数据模型的表头获取Name
    QBarSet *setMath = new QBarSet(theModel->horizontalHeaderItem(colNoMath)->text());
    QBarSet *setChinese = new QBarSet(theModel->horizontalHeaderItem(colNoChinese)->text());
    QBarSet *setEnglish= new QBarSet(theModel->horizontalHeaderItem(colNoEnglish)->text());

    QLineSeries *Line = new QLineSeries(); //创建一个QLineSeries序列用于显示平均分
    Line->setName(theModel->horizontalHeaderItem(colNoAverage)->text());
    QPen    pen;
    pen.setColor(Qt::red);
    pen.setWidth(2);
    Line->setPen(pen);
    //    lineseries->setPointLabelsVisible(true);
    //    lineseries->setPointLabelsFormat("@yPoint");

    for(int i=0;i<theModel->rowCount();i++)
    {//从数据模型获取数据
        setMath->append(theModel->item(i,colNoMath)->text().toInt()); //数学
        setChinese->append(theModel->item(i,colNoChinese)->text().toInt()); //语文
        setEnglish->append(theModel->item(i,colNoEnglish)->text().toInt()); //英语
        Line->append(QPointF(i,theModel->item(i,colNoAverage)->text().toFloat()));  //平均分
    }

    //创建一个柱状图序列 QBarSeries, 并添加三个数据集
    QBarSeries *series = new QBarSeries();
    series->append(setMath);
    series->append(setChinese);
    series->append(setEnglish);
    //    series->setLabelsVisible(true);
    //    series->setLabelsPosition(QAbstractBarSeries::LabelsOutsideEnd);// LabelsCenter
    //    series->setLabelsPosition(QAbstractBarSeries::LabelsCenter);// LabelsCenter

    //    lineseries->setPointLabelsVisible(true);
    //    lineseries->setPointLabelsFormat("@yPoint");

    chart->addSeries(series); //添加柱状图序列
    chart->addSeries(Line); //添加折线图序列

    //用于横坐标在字符串列表,即学生姓名
    QStringList categories;
    for (int i=0;i<theModel->rowCount();i++)
        categories <<theModel->item(i,colNoName)->text();

    //用于柱状图的坐标轴
    QBarCategoryAxis *axisX = new QBarCategoryAxis();
    axisX->append(categories); //添加横坐标文字列表
    //    chart->createDefaultAxes();
    chart->setAxisX(axisX, series); //设置横坐标
    chart->setAxisX(axisX, Line);//设置横坐标
    axisX->setRange(categories.at(0), categories.at(categories.count()-1)); //这只坐标轴范围

    //数值型坐标作为纵轴
    QValueAxis *axisY = new QValueAxis;
    axisY->setRange(0, 100);
    axisY->setTitleText("分数");
    axisY->setTickCount(6);//11
    axisY->setLabelFormat("%.0f"); //标签格式
    //    axisY->setGridLineVisible(false);
    //    axisY->setMinorTickCount(4);
    chart->setAxisY(axisY, series); //为
    chart->setAxisY(axisY, Line);

    //    lineseries->setPointLabelsVisible(true);
    //    lineseries->setPointLabelsFormat("@yPoint");

    chart->legend()->setVisible(true); //显示图例
    chart->legend()->setAlignment(Qt::AlignBottom); //图例显示在下方

}

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    theModel=new QStandardItemModel(iniDataRowCount,fixedColumnCount,this);
    iniData();
    surveyData();

    //数据模块的 itemChanged信号与自定义的槽函数关联,用于自动计算平均分
    connect(theModel,SIGNAL(itemChanged(QStandardItem *)),
            this,SLOT(on_itemChanged(QStandardItem *)));
    ui->tableView->setModel(theModel);

    iniBarChart();
}

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

void MainWindow::on_actGenData_triggered()
{
    iniData();
    surveyData();
}

void MainWindow::on_actTongJi_triggered()
{
    surveyData();
}

void MainWindow::on_itemChanged(QStandardItem *item)
{
    //自动计算平均分
    if ((item->column()<colNoMath) || (item->column()>colNoEnglish))
        return; //如果被修改的item不是数学、语文、英语,就退出

    int rowNo=item->row(); //获取数据的行编号

    qreal   avg=0;
    QStandardItem   *aItem;
    for (int i=colNoMath;i<=colNoEnglish;i++)
    { //获取三个分数的和
        aItem=theModel->item(rowNo,i);
        avg+=aItem->text().toDouble();
    }
    avg=avg/3; //计算平均分

    aItem=theModel->item(rowNo,colNoAverage); //获取平均分数据的item
    aItem->setText(QString::asprintf("%.1f",avg)); //更新平均分数据
    //当数据发生变化时,更新柱状图和重新统计学生分数情况
    on_btnBuildBarChart_clicked();
    surveyData();
}

void MainWindow::on_btnBuildBarChart_clicked()
{//创建柱状图
    buildBarChart();
}

​ 一个柱状图有多个数据集组成,在此创建3个QBarSet数据集,分别对应数学、语文、英语3门课的分数。柱状图的数据集类是QBarSet,创建对象时使用了数据模型的列标题作为数据集的名称,这个名称会显示在图例中。显示平均分使用QLineSeries序列,即折线序列。

​ 创建3个QBarSet数据集和折线序列后,遍历数据模型将数据添加到数据集或折线序列。如数学数据的添加

setMath->append(theModel->item(i,colNoMath)->text().toInt());

​ 为3个QBarSet数据集添加完数据后创建一个QBarSeries序列,并将3个数据集添加到这个QBarSeries序列

    //创建一个柱状图序列 QBarSeries, 并添加三个数据集
    QBarSeries *series = new QBarSeries();
    series->append(setMath);
    series->append(setChinese);
    series->append(setEnglish);
柱状图相关的主要类介绍
QBarSet 用于创建柱状图的数据集
QBarSeries 柱状图序列,一个柱状图序列一般包含多个QBarSet数据集
QBarCategoryAxis 柱状图分类坐标,以文字标签形式表示的坐标

下面时以上三个类的主要函数接口

QBarSet
在这里插入图片描述

QBarSeries
在这里插入图片描述

QBarCategoryAxis
在这里插入图片描述

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值