绘制饼图详细过程

QtCharts绘制饼图

说明:qcustomplot模块没有绘制饼图的接口和模块,所以用Qt官方自带的QtCharts进行绘制。绘制出来还挺美观。

1 模块导入

c++ 复制代码
QT       += charts
c++ 复制代码
QT_BEGIN_NAMESPACE

以上这两行代码必须得加

2 总体代码

  • widget.h
c++ 复制代码
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtCharts>
#include <QChartView>
#include "qcustomplot.h"
#include <QTimer>
#include <QRandomGenerator>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
QT_CHARTS_USE_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT

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

public:
    void paintPie(QChartView *chartView);

private:
    Ui::Widget *ui;
    QTimer *timer;
};
#endif // WIDGET_H
  • widget.cpp
c++ 复制代码
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    paintPie(ui->graphicsView);
    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this,[this]()
    {
        // 预定义的类别名称数组
        static const QStringList categoryNames = {
               "Search Engine",
               "Direct",
               "Email",
               "Union Ads",
               "Video Ads"
           };
        QPieSeries *series = static_cast<QPieSeries *>(ui->graphicsView->chart()->series().at(0));
        QList<QPieSlice*> slices = series->slices();
        if (slices.size() >= 5)
        {
            slices[0]->setValue(QRandomGenerator::global()->bounded(10, 100));
            slices[1]->setValue(QRandomGenerator::global()->bounded(10, 100));
            slices[2]->setValue(QRandomGenerator::global()->bounded(10, 100));
            slices[3]->setValue(QRandomGenerator::global()->bounded(10, 100));
            slices[4]->setValue(QRandomGenerator::global()->bounded(10, 100));
        }
        for (int i = 0; i < slices.size(); i++)
        {
            qreal percent = (slices[i]->value() / series->sum()) * 100.0;
//            修改了这句代码,slice->label()会获取标签值,然后在标签值后不断追加数据
//            label = QString("%1\n%2%").arg(slice->label()).arg(percent, 0, 'f', 1);
            QString label = QString("%1\n%2%").arg(categoryNames[i]).arg(percent, 0, 'f', 1);
            slices[i]->setLabel(label);
            slices[i]->setLabelVisible(true);
            slices[i]->setLabelArmLengthFactor(0.05);
            slices[i]->setLabelPosition(QPieSlice::LabelOutside);
        }

    });
    timer->start(1000);
}

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

void Widget::paintPie(QChartView *chartView)
{
    // 创建饼图对象
    QPieSeries *series = new QPieSeries();
    series->setHoleSize(0.35);  // 空心圆大小(0-1)
    series->setPieSize(0.7);     // 饼图相对视图的大小

    // 创建Chart画布
    QChart *chart = new QChart();
    chartView->setBackgroundBrush(QBrush(QColor(Qt::black)));
    chart->setBackgroundBrush(QBrush(QColor(Qt::black)));
    chart->addSeries(series);
    chart->setAnimationOptions(QChart::AllAnimations); // 设置显示时的动画效果
    chart->setTitle("系统CPU利用率");
    chart->setTitleFont(QFont("Arial", 14, QFont::Bold));
    // 将参数设置到画布
    chartView->setChart(chart);
    chartView->setRenderHint(QPainter::Antialiasing);
    chartView->chart()->setTheme(QChart::ChartTheme(0));
    chartView->setRubberBand(QChartView::RectangleRubberBand);  // 矩形缩放
    // 添加数据切片
    QPieSlice *slice1 = series->append("Search Engine", 1048);
    QPieSlice *slice2 = series->append("Direct", 735);
    QPieSlice *slice3 = series->append("Email", 580);
    QPieSlice *slice4 = series->append("Union Ads", 484);
    QPieSlice *slice5 = series->append("Video Ads", 300);

    // 配置每个切片的样式
    slice1->setColor(QColor(92, 123, 217));
    slice2->setColor(QColor(159, 224, 128));
    slice3->setColor(QColor(255, 220, 96));
    slice4->setColor(QColor(255, 112, 112));
    slice5->setColor(QColor(126, 211, 244));

    // 设置标签格式:显示百分比和名称
    for (auto slice : series->slices()) {
       qreal percent = (slice->value() / series->sum()) * 100.0;
       QString label = QString("%1\n%2%").arg(slice->label()).arg(percent, 0, 'f', 1);
       slice->setLabel(label);
       slice->setLabelVisible(true);
       slice->setLabelArmLengthFactor(0.05);  // 标签连接线长度
       slice->setLabelPosition(QPieSlice::LabelOutside);  // 标签在外部
//       slice->setBorderWidth(2);  // 切片边框宽度
    }

    // 配置图例
    chart->legend()->setVisible(true);
    chart->legend()->setAlignment(Qt::AlignTrailing);
    chart->legend()->setFont(QFont("Arial", 9));


    // 连接悬停信号(突出显示效果)
    connect(series, &QPieSeries::hovered, [](QPieSlice *slice, bool state)
    {
       if (state)
       {
           slice->setExploded(true);      // 突出显示
           slice->setLabelVisible(true);  // 确保标签可见
       }
       else
       {
           slice->setExploded(false);
           slice->setPen(QPen(Qt::NoPen));
       }
    });


}

3 逐段代码看效果

c++ 复制代码
// 创建饼图对象
QPieSeries *series = new QPieSeries();
series->setHoleSize(0.35);  // 空心圆大小(0-1)
series->setPieSize(0.7);     // 饼图相对视图的大小

// 创建Chart画布
QChart *chart = new QChart();
// 将饼图对象加入画布中
chart->addSeries(series);

// 设置界面打开时有动画显示
chart->setAnimationOptions(QChart::AllAnimations); // 设置显示时的动画效果
chart->setTitle("饼图示例");
chart->setTitleFont(QFont("Arial", 14, QFont::Bold));
// 将画布设置到视图
chartView->setChart(chart);
chartView->setRenderHint(QPainter::Antialiasing);
chartView->chart()->setTheme(QChart::ChartTheme(0));
chartView->setRubberBand(QChartView::RectangleRubberBand);  // 矩形缩放

上述代码是标准操作流程

接下来才是操作饼图

c++ 复制代码
// 添加数据切片
QPieSlice *slice1 = series->append("Search Engine", 1048);
QPieSlice *slice2 = series->append("Direct", 735);
QPieSlice *slice3 = series->append("Email", 580);
QPieSlice *slice4 = series->append("Union Ads", 484);
QPieSlice *slice5 = series->append("Video Ads", 300);
// 配置每个切片的样式
slice1->setColor(QColor(92, 123, 217));
slice2->setColor(QColor(159, 224, 128));
slice3->setColor(QColor(255, 220, 96));
slice4->setColor(QColor(255, 112, 112));
slice5->setColor(QColor(126, 211, 244));
c++ 复制代码
series->setHoleSize(0);  // 空心圆大小(0-1)
series->setPieSize(0.7);     // 饼图相对视图的大小
c++ 复制代码
series->setHoleSize(1);  // 空心圆大小(0-1)
series->setPieSize(0.7);     // 饼图相对视图的大小

这样,基础的饼图就绘制出来了,接下来是配置

c++ 复制代码
// 设置标签格式:显示百分比和名称
for (auto slice : series->slices())
{
	qreal percent = (slice->value() / series->sum()) * 100.0;
    QString label = QString("%1\n%2%").arg(slice->label()).arg(percent, 0, 'f', 1);
    slice->setLabel(label);
    slice->setLabelVisible(true);
    slice->setLabelArmLengthFactor(0.05);  // 标签连接线长度
    slice->setLabelPosition(QPieSlice::LabelOutside);  // 标签在外部
   // slice->setBorderWidth(2);  // 切片边框宽度
}
c++ 复制代码
slice->setLabelPosition(QPieSlice::LabelInsideNormal);
c++ 复制代码
// 配置图例
chart->legend()->setVisible(true);
chart->legend()->setAlignment(Qt::AlignTrailing);
chart->legend()->setFont(QFont("Arial", 9));
c++ 复制代码
// 连接悬停信号(突出显示效果)
connect(series, &QPieSeries::hovered, [](QPieSlice *slice, bool state)
{
   if (state)
   {
       slice->setExploded(true);      // 突出显示
       slice->setLabelVisible(true);  // 确保标签可见
   }
   else
   {
       slice->setExploded(false);
       slice->setPen(QPen(Qt::NoPen));
   }
});

4 让饼图动态显示

c++ 复制代码
// 首先,肯定要有一个定时器吧
timer = new QTimer(this);

connect(timer, &QTimer::timeout, this,[this]()
{
    // 预定义的类别名称数组
    static const QStringList categoryNames = {
               "Search Engine",
               "Direct",
               "Email",
               "Union Ads",
               "Video Ads"
     };
     // 获取饼图的切片
     QPieSeries *series = static_cast<QPieSeries *>(ui->graphicsView->chart()->series().at(0));
     QList<QPieSlice*> slices = series->slices();
     if (slices.size() >= 5)
     {
     	// 这里直接用索引,没有用series->append
     	slices[0]->setValue(QRandomGenerator::global()->bounded(10, 100));
        slices[1]->setValue(QRandomGenerator::global()->bounded(10, 100));
        slices[2]->setValue(QRandomGenerator::global()->bounded(10, 100));
        slices[3]->setValue(QRandomGenerator::global()->bounded(10, 100));
        slices[4]->setValue(QRandomGenerator::global()->bounded(10, 100));
     }
     for (int i = 0; i < slices.size(); i++)
     {
     	qreal percent = (slices[i]->value() / series->sum()) * 100.0;
//            修改了这句代码,slice->label()会获取标签值,然后在标签值后不断追加数据
//            label = QString("%1\n%2%").arg(slice->label()).arg(percent, 0, 'f', 1);
        QString label = QString("%1\n%2%").arg(categoryNames[i]).arg(percent, 0, 'f', 1);
        slices[i]->setLabel(label);
        slices[i]->setLabelVisible(true);
        slices[i]->setLabelArmLengthFactor(0.05);
        slices[i]->setLabelPosition(QPieSlice::LabelOutside);
    }

});
timer->start(1000);
相关推荐
小徐不徐说34 分钟前
每日一算:华为-批萨分配问题
数据结构·c++·算法·leetcode·华为·动态规划·后端开发
武子康2 小时前
Java-82 深入浅出 MySQL 内部架构:服务层、存储引擎与文件系统全覆盖
java·开发语言·数据库·学习·mysql·spring·微服务
惜.己2 小时前
pytest中使用skip跳过某个函数
开发语言·python·测试工具·pytest
姜暮儿2 小时前
C++ 性能优化
开发语言·c++
啊呦.超能力3 小时前
QT开发---多线程编程
开发语言·qt
铭哥的编程日记3 小时前
《从C风格到C++风格:内存管理的进化之路》
开发语言·c++
秃了也弱了。3 小时前
reflections:Java非常好用的反射工具包
java·开发语言
Joker—H5 小时前
【Java】Reflection反射(代理模式)
java·开发语言·经验分享·代理模式·idea
程序员编程指南5 小时前
Qt 与 SQLite 嵌入式数据库开发
c语言·数据库·c++·qt
阿里巴巴淘系技术团队官网博客5 小时前
面向互联网2C业务的分布式类Manus Java框架
java·开发语言·分布式