做得比较low
cpp
#ifndef TEST_POWER_H
#define TEST_POWER_H
#include <QWidget>
#include <QtMath>
#include <QPainter>
#include <QPushButton>
#include <QVector>
#include <cmath>
namespace Ui {
class test_power;
}
struct PieData
{
QString name; //名称
int num; //数量
QColor color; //颜色
PieData(QString name,int num,QColor color)
{
this->name = name;
this->num = num;
this->color = color;
}
};
struct shanxing{
double zhanbi;
double start_x;
double start_y;
double end_x;
double end_y;
};
class test_power : public QWidget
{
Q_OBJECT
public:
explicit test_power(int dongli=0,int zhaoming=0,int kongtiao=0,int teshu=0,int clicked=1000,QWidget *parent = nullptr);
~test_power();
QVector<QPointF> a;
int m_proportion[4],clicked_code;
void initWidget();
//圆环图各参数函数接口
void setRadiusLong(int radius_long);
void setRadius(int radius);
void setInnerWidth(int width);
void setCenter(QPoint center);
void setStartAngle(qreal startAngle);
void setTextDistance(int textDistance);
void setPieData(QVector<PieData> vData);
void refreshChart();
shanxing my_shanxing[4];
int m_radius,m_radius_long; //外圆半径
int m_innerWidth; //圆环内径
QPoint m_center; //圆心坐标
qreal m_startAngle; //圆环绘制起点
int m_textDistance; //文本与圆心的距离
qreal m_totality; //总数
QVector<PieData> m_vData; //数据容器
QPointF getArcPoint(const QPoint ¢er, int radius, double angle);
void calculateArcPoints(QPainter &painter, const QPoint ¢er, int radius, double startAngle, double sweepLength,int i);
protected:
void paintEvent(QPaintEvent *);
void mousePressEvent(QMouseEvent *event);
private slots:
// void on_pb_test_clicked();
// void pb_clicked();
private:
Ui::test_power *ui;
signals:
//传出你想要传出的参数
void notice_clicked(int);
};
#endif // TEST_POWER_H
cpp
#include "test_power.h"
#include "ui_test_power.h"
#include <QDebug>
#include <QMouseEvent>
test_power::test_power(int dongli,int zhaoming,int kongtiao,int teshu,int clicked,QWidget *parent) :
QWidget(parent),
ui(new Ui::test_power)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
setWindowFlags(Qt::FramelessWindowHint);
this->initWidget();
m_proportion[0] = dongli;
m_proportion[1] = zhaoming;
m_proportion[2] = kongtiao;
m_proportion[3] = teshu;
clicked_code = clicked;
//设置圆环各参数
this->setRadius(160);
this->setRadiusLong(190);
this->setInnerWidth(0); //设为0即为饼图
this->setCenter(QPoint(275,275));
this->setStartAngle(0); //区域绘制方向为逆时针
this->setTextDistance(210);
this->refreshChart();
}
test_power::~test_power()
{
delete ui;
}
//初始化界面
void test_power::initWidget()
{
//初始化变量
m_radius = 0;
m_radius_long=0;
m_innerWidth = 0;
m_center = QPoint(0,0);
m_startAngle = 0;
m_textDistance = 0;
m_totality = 0;
m_vData.clear();
}
//设置外圆长半径
void test_power::setRadiusLong(int radius_long)
{
m_radius_long=radius_long;
}
//设置外圆半径
void test_power::setRadius(int radius)
{
m_radius = radius;
}
//设置圆环内径
void test_power::setInnerWidth(int width)
{
m_innerWidth = width;
}
//设置圆心
void test_power::setCenter(QPoint center)
{
m_center = center;
}
//设置圆环绘制起点
void test_power::setStartAngle(qreal startAngle)
{
m_startAngle = startAngle;
}
//设置文本与圆心的距离
void test_power::setTextDistance(int textDistance)
{
m_textDistance = textDistance;
}
//设置饼图数据
void test_power::setPieData(QVector<PieData> vData)
{
//获取数据
m_vData = vData;
//获取总数
m_totality = 0;
for(int i=0;i<m_vData.size();i++)
{
m_totality += m_vData[i].num;
}
this->update();
}
//更新饼图
void test_power::refreshChart()
{
//设置圆环图各区域数据名称及颜色
QVector<PieData> vData;
QColor m_colors[4] = {QColor(237,117,57),QColor(111,173,30),QColor(198,49,16),QColor(248,206,34)};
QString m_names[4] = {"quyu1","quyu2","quyu3","quyu4"};
for(int i=0;i<4;i++)
{
if(!m_names[i].isEmpty() && m_proportion[i]>0)
{
PieData data = PieData(QString("%1\n%2").arg(m_names[i]).arg(QString::number(m_proportion[i])+"%"),m_proportion[i],m_colors[i]);
vData.push_back(data);
}
}
this->setPieData(vData);
}
//重写绘图事件
void test_power::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true); //抗锯齿
//绘制圆角背景
painter.setBrush(Qt::transparent);
painter.setPen(Qt::NoPen); //去除背景边框
painter.drawRoundedRect(10,10,360,360,8,8);
//绘制饼图
qreal startAngle = m_startAngle; //绘制起点
qreal spanAngle = 0; //各区域占比,覆盖角度
for(int i=0;i<m_vData.size();i++)
{
painter.setPen(m_vData[i].color);
painter.setBrush(m_vData[i].color);
if(m_totality) //防止总数为0
{
spanAngle = m_vData[i].num * 360 / m_totality;
my_shanxing[i].zhanbi = m_vData[i].num / m_totality;
}
if(i==clicked_code){
painter.drawPie(m_center.x() - m_radius_long,m_center.y() - m_radius_long,m_radius_long * 2,m_radius_long * 2,startAngle * 16,spanAngle * 16);
}else{
painter.drawPie(m_center.x() - m_radius,m_center.y() - m_radius,m_radius * 2,m_radius * 2,startAngle * 16,spanAngle * 16);
}
calculateArcPoints(painter, m_center,m_radius,startAngle,spanAngle,i);
startAngle += spanAngle;
}
//绘制区域名称和占比
startAngle = m_startAngle;
spanAngle = 0;
for(int i=0;i<m_vData.size();i++)
{
painter.setPen(QColor("#ffffff"));
painter.setFont(QFont("STSongti-SC-Bold, STSongti-SC",16));
if(m_totality)
{
spanAngle = m_vData[i].num * 360 / m_totality;
}
int textAngle = startAngle + spanAngle / 2;
QString text = QString("%1").arg(m_vData[i].name);
int textWidth = painter.fontMetrics().horizontalAdvance(text);
int textHeight = painter.fontMetrics().height();
int textX = m_center.x() + m_textDistance * qCos(textAngle * M_PI / 180) - textWidth / 2;
int textY = m_center.y() - m_textDistance * qSin(textAngle * M_PI / 180) + textHeight / 2;
startAngle += spanAngle;
//绘制文本
QRect rect(textX,textY - textHeight,textWidth + 10,textHeight * 2);
painter.drawText(rect,Qt::AlignCenter,text);
//绘制连接线,文本要靠近对应区域,需要修改连接线终点位置
painter.setPen(m_vData[i].color);
int lineStartX = m_center.x() + (m_radius - 10) * qCos(textAngle * M_PI / 180);
int lineStartY = m_center.y() - (m_radius - 10) * qSin(textAngle * M_PI / 180);
int lineEndX = 0;
int lineEndY = 0;
if(textX < lineStartX) //文本在左边
{
//可自行根据实际进行位置偏移的修改
lineEndX = textX + textWidth/2;
if(textY < lineStartY) //文本在上边
{
lineEndY = textY + textHeight + 5;
}
else
{
lineEndY = textY - textHeight - 5;
}
}
else
{
lineEndX = textX + textWidth/2;
if(textY < lineStartY)
{
lineEndY = textY;
}
else
{
lineEndY = textY - textHeight - 5;
}
}
painter.drawLine(lineStartX,lineStartY,lineEndX,lineEndY);
//绘制终点
painter.setPen(QPen(m_vData[i].color,5));
painter.drawPoint(lineEndX,lineEndY);
//将终点设为空心圆
//painter.drawEllipse(QPoint(lineEndX,lineEndY),5,5);
//painter.setPen(QPen(QColor("#FFFFFF"),1));
//painter.setBrush(QColor("#FFFFFF"));
//painter.drawEllipse(QPoint(lineEndX,lineEndY),3,3);
}
//绘制内圆,将饼图变为圆环
painter.setPen(QPen(QColor("#FFFFFF"),10));
painter.setBrush(QColor("#FFFFFF"));
painter.drawEllipse(m_center,m_innerWidth,m_innerWidth);
}
void test_power::mousePressEvent(QMouseEvent *event)
{
QPoint mousePos = event->pos();
double x = mousePos.x()- m_center.x();
if(x==0){
return;
}
double y = m_center.y() - mousePos.y();
if(y==0){
return;
}
if( x*x + y*y < m_radius*m_radius){
// 输出或使用坐标点
// qDebug() << "Mouse pressed at position:" << x << "," << y;
if(x>0 && y>0 ){
double zhanbi=0;
for (int i=0;i<4;i++){
zhanbi += my_shanxing[i].zhanbi;
if(zhanbi<0.25 && y/x>my_shanxing[i].start_y/my_shanxing[i].start_x && y/x<my_shanxing[i].end_y/my_shanxing[i].end_x){
qDebug()<<"clicked ============"<<i;
emit notice_clicked(i);
return;
}
if(zhanbi>=0.25) {
qDebug()<<"clicked ============"<<i;
emit notice_clicked(i);
return;
}
}
}else if(x<0 && y>0 ){
double zhanbi=0;
for (int i=0;i<4;i++){
zhanbi += my_shanxing[i].zhanbi;
if(zhanbi>0.25 && zhanbi<=0.5){
if(my_shanxing[i].start_x>=0){
//起始位置在第一象限
if(y/x<my_shanxing[i].end_y/my_shanxing[i].end_x){
qDebug()<<"clicked ============"<<i;
emit notice_clicked(i);
return;
}
}else{
//起始位置在第二象限
if(y/x>my_shanxing[i].start_y/my_shanxing[i].start_x && y/x<my_shanxing[i].end_y/my_shanxing[i].end_x){
qDebug()<<"clicked ============"<<i;
emit notice_clicked(i);
return;
}
}
}
if(zhanbi>0.5) {
qDebug()<<"clicked ============"<<i;
emit notice_clicked(i);
return;
}
}
}else if(x<0 && y<0 ){
double zhanbi=0;
for (int i=0;i<4;i++){
zhanbi += my_shanxing[i].zhanbi;
if(zhanbi>0.5 && zhanbi<=0.75){
if(my_shanxing[i].start_y>=0){
//起始位置在第一或者第二象限
if(y/x<my_shanxing[i].end_y/my_shanxing[i].end_x){
qDebug()<<"clicked ============"<<i;
return;
}
}else{
//起始位置在第三象限
if(y/x>my_shanxing[i].start_y/my_shanxing[i].start_x && y/x<my_shanxing[i].end_y/my_shanxing[i].end_x){
qDebug()<<"clicked ============"<<i;
return;
}
}
}
if(zhanbi>0.75) {
qDebug()<<"clicked ============"<<i;
emit notice_clicked(i);
return;
}
}
}else if(x>0 && y<0 ){
double zhanbi=0;
for (int i=0;i<4;i++){
zhanbi += my_shanxing[i].zhanbi;
if(zhanbi>0.75){
if(my_shanxing[i].start_y>=0 || (my_shanxing[i].start_y<=0 && my_shanxing[i].start_x<=0)){
//起始位置位于一或者二或者三象限
if(y/x<my_shanxing[i].end_y/my_shanxing[i].end_x){
qDebug()<<"clicked ============"<<i;
emit notice_clicked(i);
return;
}
}else{
// qDebug()<<"iiiiiiiiiiiiiiiiii="<<i<<"=="<<y/x<<"==="<<my_shanxing[i].start_y/my_shanxing[i].start_x<<"------"<<my_shanxing[i].end_y/my_shanxing[i].end_x;
// qDebug()<<i<<"==y="<<y<<" x="<<x<<"===y="<<my_shanxing[i].start_y<<"===x"<<my_shanxing[i].start_x<<"------y="<<my_shanxing[i].end_y<<" x="<<my_shanxing[i].end_x;
if(y/x>my_shanxing[i].start_y/my_shanxing[i].start_x && y/x<my_shanxing[i].end_y/my_shanxing[i].end_x){
qDebug()<<"clicked ============"<<i;
emit notice_clicked(i);
return;
}
}
}
}
}
}
}
void test_power::calculateArcPoints(QPainter &painter, const QPoint ¢er, int radius, double startAngle, double sweepLength,int inum) {
QPointF startPoint = getArcPoint(center, radius, startAngle);
QPointF endPoint = getArcPoint(center, radius, startAngle + sweepLength);
my_shanxing[inum].start_x=startPoint.x()-m_center.x();
my_shanxing[inum].start_y= m_center.y()-startPoint.y();
my_shanxing[inum].end_x= endPoint.x()-m_center.x();
my_shanxing[inum].end_y= m_center.y()-endPoint.y();
// 这里可以处理startPoint和endPoint,例如绘制线条或进行其他操作
// painter.drawLine(startPoint, endPoint); // 示例:绘制扇形边界线
// qDebug()<<"startPoint x="<<my_shanxing[inum].start_x<<" y="<<my_shanxing[inum].start_y;
// qDebug()<<"endPoint x="<<my_shanxing[inum].end_x<<" y="<<my_shanxing[inum].end_y;
}
QPointF test_power::getArcPoint(const QPoint ¢er, int radius, double angle) {
double radian = angle * M_PI / 180; // 将角度转换为弧度
return QPointF(center.x() + radius * cos(radian), center.y() - radius * sin(radian));
}

ui里面就很简单只要设置尺寸就行了
调用时候的代码
//加载饼状图
dongli=20;zhaoming=30;kongtiao=40;teshu=20;
my_test_power = new test_power(dongli,zhaoming,kongtiao,teshu);
connect(my_test_power,SIGNAL(notice_clicked(int)),this,SLOT(refresh_power(int)));
test_power_list.append(my_test_power);
glayout_power = new QVBoxLayout();
glayout_power->addWidget(my_test_power);
ui->frame->setLayout(glayout_power);