绘制饼图详细过程

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);
相关推荐
西阳未落3 小时前
C++基础(21)——内存管理
开发语言·c++·面试
我的xiaodoujiao3 小时前
Windows系统Web UI自动化测试学习系列2--环境搭建--Python-PyCharm-Selenium
开发语言·python·测试工具
callJJ3 小时前
从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(2)
java·开发语言·后端·spring·ioc·di
超级大福宝3 小时前
使用 LLVM 16.0.4 编译 MiBench 中的 patricia遇到的 rpc 库问题
c语言·c++
wangjialelele3 小时前
Linux中的线程
java·linux·jvm·c++
hsjkdhs5 小时前
万字详解C++之构造函数析构函数
开发语言·c++
Lin_Aries_04215 小时前
容器化简单的 Java 应用程序
java·linux·运维·开发语言·docker·容器·rpc
SELSL6 小时前
SQLite3的API调用实战例子
linux·数据库·c++·sqlite3·sqlite实战
什么半岛铁盒6 小时前
C++项目:仿muduo库高并发服务器-------Channel模块实现
linux·服务器·数据库·c++·mysql·ubuntu
techdashen6 小时前
12分钟讲解Python核心理念
开发语言·python