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> 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!!!!