Qt 实现3维饼状图

Qt 实现3维饼状图

一.思路

自从Qt5 引入 QChart 模块后,qt就大大增强了画图表的功能,如饼状图、柱形图、折线图、面积图等等。要知道,qt4时代,画个图表要不通过QPainter来画,要不通过第三方库来画,都是比较麻烦的。而qt5可以轻松画出二维的图表。
那么,如何画3D的饼状图图呢,此处介绍一种比较神奇的方法:
  我们知道,一个圆柱体,可以看成是N个圆在Z轴方向叠加而成,所以,要画一个高度为H的圆柱体,那么,只需要画H个依次向上叠加的圆即可,再配以不同的颜色。

二.实现

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H


#include <QMainWindow>
#include <QPainter>

#define PI_VALUE 3.1415926

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    void drawText(QPainter *painter,QRectF rect,int startAngle,int spanAngle,QString text);

protected:
    void paintEvent( QPaintEvent* ev );
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <math.h>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

//画文本
//关键是求文本起始坐标位置。此处,取扇形中分线上的中点。
void MainWindow::drawText(QPainter *painter,QRectF rect, int startAngle, int spanAngle, QString text)
{
    double rX = rect.width() / 2;   //圆弧半径  x方向
    double rY = rect.height() / 2;  //圆弧半径  Y方向

    //圆心
    double x0 = rect.x() + rX;
    double y0 = rect.y() + rY;
    qDebug()<<"_______________________";
    qDebug()<<"x0,y0: "<<x0<<y0;

    double mx,my;  //画文字的坐标位置
    int endAngle = startAngle + spanAngle / 2;
    if(spanAngle > 360)
        spanAngle -= 360;

    qDebug()<<"endAngle: "<<endAngle;
    if(endAngle == 0)
    {
        mx = x0 + rX / 2;
        my = y0;
    }
    else if(endAngle == 180)
    {
        mx = x0 - rX / 2;
        my = y0;
    }
    else if(endAngle == 90)
    {
        mx = x0;
        my = y0 - rY / 2;
    }
    else if(endAngle == 270)
    {
        mx = x0;
        my = y0 + rY / 2;
    }
    else if(endAngle > 0 && endAngle < 90)
    {
        mx = x0 + rX * cos(endAngle * PI_VALUE / 180) / 2;
        my = y0 - rY * sin(endAngle * PI_VALUE / 180) / 2;
    }
    else if(endAngle > 90 && endAngle < 180)
    {
        mx = x0 - rX * cos((180 - endAngle) * PI_VALUE / 180) / 2;
        my = y0 - rY * sin((180 - endAngle) * PI_VALUE / 180) / 2;
    }
    else if(endAngle > 180 && endAngle < 270)
    {
        mx = x0 - rX * cos((270 - endAngle) * PI_VALUE / 180) / 2;
        my = y0 + rY * sin((270 - endAngle) * PI_VALUE / 180) / 2;
    }
    else if(endAngle > 270 && endAngle < 360)
    {
        mx = x0 + rX * cos((360 - endAngle) * PI_VALUE / 180) / 2;
        my = y0 + rY * sin((360 - endAngle) * PI_VALUE / 180) / 2;
    }
    else
    {
        return;
    }

    int textSpace = 5;  //Y轴向下偏移一点点,看起来更加好
    painter->drawText(mx, my + textSpace, text);
}

void MainWindow::paintEvent(QPaintEvent *ev)
{
    QPainter painter(this);
    // 去除画笔
    painter.setPen(Qt::NoPen);
    // 设置反锯齿
    painter.setRenderHint(QPainter::Antialiasing);

    //******************************************** 圆饼图 *****************************************//
    int widWidth = this->width();
    int widHeight = this->height();

    int spaceH = 10;
    int spaceV = 0;
    int rectHeight = widHeight * 3 / 4;    //圆弧所在矩形高度
    int chartWidth = widWidth - 2 * spaceH;
    int chartHeight = widHeight - rectHeight - 2 * spaceV - spaceV;

    int normal = 20;     //正常
    int offline = 4;    //离线
    int abnormal = 3;   //异常
    int total = normal + offline + abnormal;

    //颜色
    QColor colorNormal = QColor(27,203,204);
    QColor colorDarkNormal = QColor(36,124,121);
    QColor colorOffline = QColor(225,180,225);
    QColor colorDarkOffline = QColor(144,118,144);
    QColor colorAbnormal = QColor(219,224,120);
    QColor colorDarkAbnormal = QColor(142,144,77);

    // 顶层圆面
    QRectF rect_top(spaceH, spaceV, chartWidth, rectHeight);
    // 底层圆面
    QRectF rect_bottom(spaceH, widHeight - rectHeight - 2 * spaceV, chartWidth, rectHeight);

    painter.setBrush(colorDarkNormal);
    // 绘制底层圆面
    painter.drawEllipse(rect_bottom);

    //计算3种情况扇形图的起始角和旋转角
    int startAngle_1 = 0;
    int spanAngle_1 = 360 *  normal / total;

    int startAngle_2 = startAngle_1 + spanAngle_1;
    int spanAngle_2 = 360 * offline / total;

    int startAngle_3 = startAngle_2 + spanAngle_2;
    int spanAngle_3 = 360 - spanAngle_1 - spanAngle_2;
    if(spanAngle_3 < 0)
        spanAngle_3 = 0;

    //循环画 chartHeight 个 扇形(虽然效率有点低哈)
    for(int i=0; i<chartHeight; i++)
    {
        QRectF rect(rect_bottom.x(),rect_bottom.y() - i,rect_bottom.width(),rect_bottom.height());
        if(normal > 0)
        {
            painter.setBrush(colorDarkNormal);
            painter.drawPie(rect, startAngle_1 * 16, spanAngle_1 * 16);
        }
        if(offline > 0)
        {
            painter.setBrush(colorDarkOffline);
            painter.drawPie(rect, startAngle_2 * 16, spanAngle_2 * 16);
        }
        if(abnormal > 0)
        {
            painter.setBrush(colorDarkAbnormal);
            painter.drawPie(rect, startAngle_3 * 16, spanAngle_3 * 16);
        }
    }

    // 绘制顶层圆面
    painter.setBrush(colorNormal);
    painter.drawEllipse(rect_top);

    // 绘制顶层扇形
    if(normal > 0)
    {
        painter.setBrush(colorNormal);
        painter.drawPie(rect_top, startAngle_1 * 16, spanAngle_1 * 16);
    }

    if(offline > 0)
    {
        painter.setBrush(colorOffline);
        painter.drawPie(rect_top, startAngle_2 * 16, spanAngle_2 * 16);
    }

    if(abnormal > 0)
    {
        painter.setBrush(colorAbnormal);
        painter.drawPie(rect_top, startAngle_3 * 16, spanAngle_3 * 16);
    }

    //画图例........................
    QPainter painterText(this);
    QFont font;
    font.setBold(true);
    font.setPixelSize(18);
    painterText.setFont(font);
    painterText.setPen(QColor(255,255,255));

    if(normal > 0)
        drawText(&painterText,rect_top,startAngle_1,spanAngle_1,QString::number(normal));

    if(offline > 0)
        drawText(&painterText,rect_top,startAngle_2,spanAngle_2,QString::number(offline));

    if(abnormal > 0)
        drawText(&painterText,rect_top,startAngle_3,spanAngle_3,QString::number(abnormal));

    QWidget::paintEvent(ev);
}

三.效果图

如下,缩放窗口时,图像也会同步改变。
3D饼状图显示

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不是很大锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值