绘制饼图详细过程

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);
相关推荐
zh_xuan13 分钟前
c++ 单例模式
开发语言·c++·单例模式
老胖闲聊38 分钟前
Python Copilot【代码辅助工具】 简介
开发语言·python·copilot
Blossom.11842 分钟前
使用Python和Scikit-Learn实现机器学习模型调优
开发语言·人工智能·python·深度学习·目标检测·机器学习·scikit-learn
曹勖之1 小时前
基于ROS2,撰写python脚本,根据给定的舵-桨动力学模型实现动力学更新
开发语言·python·机器人·ros2
豆沙沙包?2 小时前
2025年- H77-Lc185--45.跳跃游戏II(贪心)--Java版
java·开发语言·游戏
军训猫猫头2 小时前
96.如何使用C#实现串口发送? C#例子
开发语言·c#
liuyang-neu2 小时前
java内存模型JMM
java·开发语言
利刃大大2 小时前
【在线五子棋对战】二、websocket && 服务器搭建
服务器·c++·websocket·网络协议·项目
喜欢吃燃面3 小时前
C++刷题:日期模拟(1)
c++·学习·算法
SHERlocked933 小时前
CPP 从 0 到 1 完成一个支持 future/promise 的 Windows 异步串口通信库
c++·算法·promise