QT 实现3d饼状图---3D pie chart

3d pie chart
方法一:
目前实现效果,就是用drawPie函数分别画上下间距相同并且startAgl和spanAgl相同的两组扇形(颜色可根据显示设置),请看如下效果图:
很明显这样还是不够的,其中所指位置是需要修补的区域,利用drawPolygon或者drawRect函数画所指区域即可实现修补。具体修补区域的每个点的坐标,可根据椭圆的参数方程x=acost,y=bsint(a,b分别为长短半径,t为离心角)和各个扇形的startAgl,spanAgl算出,修补后的效果图如下图所示:
这样,即可实现3d 静态饼状图效果。
部分代码如下(测试用的,写的很乱:) ):
void Myclass::paintEvent(QPaintEvent *event)
{  
       // test 3D pie
       QPainter painter;
       painter.begin(this);
      
       painter.setRenderHint(QPainter::Antialiasing, true); // 设置边缘光滑
      
       const int iRectX = 300; // left pie pos
       const int iRectY = 300;
       const int iRectW = 280;
       const int iRectH = 200;
­
       const double pi = 3.1415926;
­
       const int iSpanRed = 270;
       const int iSpanAglGreen = 15;
       const int iSpanAglBlue = 30;
       const int iSpanAglYellow = 45;
      
       const int iStartRed = 60;
       const int iStartAglGreen = -(360-iSpanRed-iStartRed);
       const int iStartAglBlue = -(-iStartAglGreen-iSpanAglGreen);
       const int iStartAglYellow = iStartAglBlue + iSpanAglYellow;
      
       // painter pie
       QRect rect(iRectX, iRectY, iRectW, iRectH);        // 左下方扇形  
       QRect rectUp(iRectX, iRectY-20, iRectW, iRectH);      // 左上方扇形  
      
       QRect rectRt(iRectX+20, iRectY, iRectW, iRectH);      // 右下方扇形  
       QRect rectRtUp(iRectX+20, iRectY-20, iRectW, iRectH);    // 右上方扇形  
      
       int startAngleRed = iStartRed * 16;
       int spanAngleRed = iSpanRed * 16;
      
       int startAngleGreen = iStartAglGreen * 16;
       int spanAngleGreen = iSpanAglGreen * 16;
      
       int startAngleBlue = iStartAglYellow * 16;
       int spanAngleBlue = iSpanAglBlue * 16;
      
       int startAngleYellow = iStartAglBlue * 16;
       int spanAngleYellow = iSpanAglYellow * 16;
      
       /// 修补用
       // 下方紅色扇形中心点位置
       int x0 = iRectX + iRectW/2;
       int y0 = iRectY + iRectH/2;
      
       int posx = x0 + (int)iRectW * (cos((360 - iStartRed - iSpanRed)*pi/180)) / 2;
       int posy = y0 + (int)iRectH * (sin((360 - iStartRed - iSpanRed)*pi/180)) / 2;
      
       int posx_1 = x0 + (int)iRectW * (cos(-iStartRed*pi/180)) / 2;
       int posy_1 = y0 + (int)iRectH * (sin(-iStartRed*pi/180)) / 2;
      
       int posx_2 = x0 + (int)iRectW * (cos(-iStartAglBlue*pi/180)) / 2;
       int posy_2 = y0 + (int)iRectH * (sin(-iStartAglBlue*pi/180)) / 2;
      
       QPoint point_1(iRectX + iRectW/2 + 20, iRectY + iRectH/2); // down
       QPoint point_2(iRectX + iRectW/2 + 20, iRectY + iRectH/2 - 20);// up
       QPoint point_3(posx + 20, posy);
       QPoint point_4(posx + 20, posy - 20);
       QPoint points[4] = {point_1, point_2, point_4, point_3};    // 修补切面平行四边形位置
      
       QPoint point_5(posx_2 + 20, posy_2);
       QPoint point_6(posx_2 + 20, posy_2 - 20);
       QPoint pots[4] = {point_3, point_4, point_6, point_5}; // 修补弧面平行四边形
­
       /// painter pie
       painter.setPen(Qt::NoPen);
       painter.setBrush(Qt::darkRed);
       painter.drawPie(rect, startAngleRed, spanAngleRed); // 左下方扇形
­
       // 右下方扇形
       painter.setBrush(Qt::darkBlue);
       painter.drawPie(rectRt, startAngleBlue, spanAngleBlue);
­
       painter.setBrush(Qt::darkYellow);
       painter.drawPie(rectRt, startAngleYellow, spanAngleYellow);
­
       painter.setBrush(Qt::darkGreen);
       painter.drawPie(rectRt, startAngleGreen, spanAngleGreen);
­
       //
       painter.setBrush(QColor(100, 255, 0, 255));
       painter.drawPolygon(points, 4);// 修补切面平行四边形
      
       painter.setBrush(Qt::darkGreen);
       painter.drawPolygon(pots, 4); // 修补弧面平行四边形
      
       painter.setBrush(Qt::darkRed);       // 修补四方形
       painter.drawRect(posx-20, posy-20, 20, 20);  // 下方四邊形
       painter.drawRect(posx_1-20, posy_1-20, 20, 20);   // 上方四邊形
      
       // 左上方扇形
       painter.setPen(Qt::black);
       painter.setBrush(Qt::red);
       painter.drawPie(rectUp, startAngleRed, spanAngleRed);
      
       // 右上方扇形
       painter.setBrush(Qt::blue);
       painter.drawPie(rectRtUp, startAngleBlue, spanAngleBlue);
­
       painter.setBrush(Qt::yellow);
       painter.drawPie(rectRtUp, startAngleYellow, spanAngleYellow);
      
       painter.setBrush(Qt::green);
       painter.drawPie(rectRtUp, startAngleGreen, spanAngleGreen);
­
       painter.end();
}
­
­现说第二种方法:
用qt的drawpie画, 在qt里面painter事件是按单位像素画的 要是设饼状图厚度为20像素,循环20次即可,画20个扇形,速度很快,这样就不需要修补了,并且可以改变每个扇形的比例和扇形个数
我做了个类,留有接口,调用只需传相应参数即可(当然根据需求可以自己添加接口喽!):
Draw3dPieChart.h
class CDraw3dPieChart : public QWidget
{
Q_OBJECT
public:
CDraw3dPieChart(QWidget *parent = 0);
public:
~CDraw3dPieChart(void);
public:
void   setPiePos(int iPosX, int iPosY);
void   setPieSize(int iWidth, int iHeight);
void   setPiePerCent(QList<double> lstPercent);
void   setChartDepth(int iDepth);
void   setChartDistance(int iDistence);// the distance of left and right???? 实现小部分扇形插入效果
­
void   paintEvent(QPaintEvent *event); // override
private:
int    m_iPosX;
int    m_iPosY;
int    m_iWidth;
int    m_iHeight;
int    m_iDepth;
int    m_iDistence;
­
QList<double> m_lstPercent;
QList<int>  m_lstSpanAgl;
QList<int>  m_lstStartAgl;
};
­
­
Draw3dPieChart.cpp
#include "Draw3dPieChart.h"
#include <math.h> ­
/*--------------------------------------------------------------------------*/
/*-------------------------- Constant Definition ---------------------------*/
/*--------------------------------------------------------------------------*/
const QColor cstDownPieColor[7] = {
          QColor(Qt::darkRed),
          QColor(Qt::darkBlue),
          QColor(Qt::darkYellow),
          QColor(Qt::darkGreen),
          QColor(Qt::darkCyan),
          QColor(Qt::darkGray),
          QColor(Qt::darkMagenta)
         };
const QColor cstUpPieColor[7] = {
          QColor(Qt::red),
          QColor(Qt::blue),
          QColor(Qt::yellow),
          QColor(Qt::green),
          QColor(Qt::cyan),
          QColor(Qt::gray),
          QColor(Qt::magenta)
         }; //这里我定义了七种颜色,最大设为七块­
­
CDraw3dPieChart::CDraw3dPieChart(QWidget *parent)
   :QWidget(parent)
{
IFPRINTF("CDraw3dPieChart::CDraw3dPieChart");
NEWOBJECT("CDraw3dPieChart");
m_iPosX = 0;
m_iPosY = 0;
m_iWidth = 0;
m_iHeight = 0;
m_iDepth = 0;
m_iDistence = 0;
m_lstPercent.clear();
m_lstSpanAgl.clear();
m_lstStartAgl.clear();
setFixedSize(929, 530);
OFPRINTF("CDraw3dPieChart::CDraw3dPieChart")
}
­
CDraw3dPieChart::~CDraw3dPieChart(void)
{
IFPRINTF("CDraw3dPieChart::~CDraw3dPieChart");
DELOBJECT("CDraw3dPieChart");
m_lstPercent.clear();
m_lstSpanAgl.clear();
m_lstStartAgl.clear();
OFPRINTF("CDraw3dPieChart::~CDraw3dPieChart");
}
­
void CDraw3dPieChart::setPiePos(int iPosX, int iPosY)
{
IFPRINTF("CDraw3dPieChart::setPiePos");
m_iPosX = iPosX;
m_iPosY = iPosY;
OFPRINTF("CDraw3dPieChart::setPiePos");
}
­
void CDraw3dPieChart::setPieSize(int iWidth, int iHeight)
{
IFPRINTF("CDraw3dPieChart::setPieSize");
­
m_iWidth = iWidth;
m_iHeight = iHeight;
OFPRINTF("CDraw3dPieChart::setPieSize");
}
­
void CDraw3dPieChart::setChartDepth(int iDepth)
{
IFPRINTF("CDraw3dPieChart::setChartDepth");
m_iDepth = iDepth;
OFPRINTF("CDraw3dPieChart::setChartDepth");
}
­
void CDraw3dPieChart::setChartDistance(int iDistence)
{
IFPRINTF("CDraw3dPieChart::setChartDistance");
m_iDistence = iDistence;
OFPRINTF("CDraw3dPieChart::setChartDistance");
}
­
void CDraw3dPieChart::setPiePerCent(QList<double> lstPercent)
{
IFPRINTF("CDraw3dPieChart::setPiePerCent");
m_lstPercent = lstPercent;
OFPRINTF("CDraw3dPieChart::setPiePerCent");
}
­
void CDraw3dPieChart::paintEvent(QPaintEvent *event)
{
IFPRINTF("CDraw3dPieChart::paintEvent");
Q_UNUSED(event);
QPainter painter;
painter.begin(this);
m_lstSpanAgl.clear();
m_lstStartAgl.clear();
m_lstStartAgl.append(60);
if (m_lstPercent.size() <= 0)
{
  return;
}
for (int i = 0; i < m_lstPercent.size(); i++)
{
  m_lstSpanAgl.append(ceil(360*m_lstPercent.at(i)));
  if (i == 0)
  {
   continue;
  }
  m_lstStartAgl.append(m_lstSpanAgl.at(i-1) + m_lstStartAgl.at(i-1));
}
painter.setRenderHint(QPainter::Antialiasing, true); //设置平滑
painter.setPen(Qt::NoPen);
­
//下部分循环m_iDepth次
for (int i = 0; i < m_iDepth; i++)
{
  QRect rectDown(m_iPosX, m_iPosY-i, m_iWidth, m_iHeight);
  for (int j = 0; j < m_lstSpanAgl.size(); j++)
  {
   painter.setBrush(cstDownPieColor[j]);
   painter.drawPie(rectDown, m_lstStartAgl.at(j)*16, m_lstSpanAgl.at(j)*16);
  }
}
­
//最上部分画一次(不同颜色)
QRect rectUp(m_iPosX, m_iPosY-m_iDepth, m_iWidth, m_iHeight);
for (int i = 0; i < m_lstPercent.size(); i++)
{
  painter.setBrush(cstUpPieColor[i]);
  painter.drawPie(rectUp, m_lstStartAgl.at(i)*16, m_lstSpanAgl.at(i)*16);
}
­
painter.end();
OFPRINTF("CDraw3dPieChart::paintEvent");
}
­
例如如此调用:
QList<double> lstPercent; //扇形个数与每个扇形的百分比
lstPercent.append(0.1);
lstPercent.append(0.3);
lstPercent.append(0.2);
lstPercent.append(0.4);
­
CDraw3dPieChart *draw3dPie = new CDraw3dPieChart(this);
draw3dPie->setPiePos(200, 200);
draw3dPie->setPieSize(280, 200);
draw3dPie->setPiePerCent(lstPercent);
draw3dPie->setChartDepth(20);
­
效果:
­
根据lstPercent传的个数和比例,可以改变比例大小和扇形个数
­
ok!!!!

你可能感兴趣的:(object,Class,qt,360,distance,math.h)