天天看點

QT 實作3d餅狀圖---3D pie chart

3d pie chart 方法一: 目前實作效果,就是用drawPie函數分别畫上下間距相同并且startAgl和spanAgl相同的兩組扇形(顔色可根據顯示設定),請看如下效果圖:

QT 實作3d餅狀圖---3D pie chart

很明顯這樣還是不夠的,其中所指位置是需要修補的區域,利用drawPolygon或者drawRect函數畫所指區域即可實作修補。具體修補區域的每個點的坐标,可根據橢圓的參數方程x=acost,y=bsint(a,b分别為長短半徑,t為離心角)和各個扇形的startAgl,spanAgl算出,修補後的效果圖如下圖所示:

QT 實作3d餅狀圖---3D pie chart

這樣,即可實作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> ­ 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); ­ 效果:

QT 實作3d餅狀圖---3D pie chart

­ 根據lstPercent傳的個數和比例,可以改變比例大小和扇形個數 ­ ok!!!!