当前位置: 首页 > news >正文

qt绘制饼状图并实现点击即放大点击部分

做得比较low

#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_OBJECTpublic: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 &center, int radius, double angle);void calculateArcPoints(QPainter &painter, const QPoint &center, 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
#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 &center, 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 &center, 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);

http://www.dtcms.com/a/270981.html

相关文章:

  • 开发制作模仿参考抄别人的小程序系统
  • Shusen Wang推荐系统学习 --召回 ItemCF
  • RabbitMQ 高级特性之事务
  • 心智模式:觉察思维定势,突破决策盲区
  • 【Ubuntu22.04安装ROS Noetic】
  • Android Notification 通过增加addAction 跳转回Service重新执行逻辑
  • 沃丰科技海外客服系统综合解决方案
  • 36氪专访丨乐橙CEO谢运:AI科技下的业务创新与长期主义下的品牌坚守
  • CD47.【C++ Dev】list的模拟实现(2)
  • RAG实战之dify源码文件解析-pdf文件解析流程
  • STM32F103ZET6的USART 中断配置详解
  • 自动化测试报告优化:jenkins+jmeter定制化HTML报告生成
  • 【LeetCode】大厂面试算法真题回忆(102)--集五福
  • Java学习第二十七部分——bug检修
  • 前端接收流式数据demo,并用markdown解析数据,包括EventSource和fetch两种方式
  • LeetCode 138题解 | 随机链表的复制
  • 力扣 hot100 Day39
  • 【保姆级喂饭教程】Windows下安装Git Flow
  • 电网的智能觉醒——人工智能重构能源生态的技术革命与公平悖论
  • JAVA策略模式demo【设计模式系列】
  • 自动化Trae Apollo参数解释的批量获取
  • 苍穹外卖项目日记(day04)
  • ASP.NET Core 8 轻松配置Serilog日志
  • 智慧码头船舶网络部署5G工业路由器无人值守场景应用
  • 无人设备遥控器之双向通讯技术篇
  • 【机器人】Aether 多任务世界模型 | 4D动态重建 | 视频预测 | 视觉规划
  • C++并发编程-11. C++ 原子操作和内存模型
  • Linux驱动学习day20(pinctrl子系统驱动大全)
  • Ubuntu防火墙缺失问题(unit firewalld.service could not be found, ubuntu 22)
  • EFK9.0.3 windows搭建