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);