很重要--轉載聲明
- 本站文章無特別說明,皆爲原創,版權全部,轉載時請用連接的方式,給出原文出處。同時寫上原做者:朝十晚八 or Twowords
- 如要轉載,請原文轉載,如在轉載時修改本文,請事先告知,謝絕在轉載時經過修改本文達到有利於轉載者的目的。
最近在搞繪圖方面的工做,說實話C++的第三方繪圖庫並不算多,總之我瞭解的有:qtcharts、ChartDirector、qwt、kdchart和QCustomPlot。這幾個庫各有利弊。緩存
下邊是繪製的餅圖展現效果,固然了不能知足大多數人的須要,我主要是在這裏提供一種思路,若是須要在繪製上有所調整的小夥伴能夠下載demo自行修改。佈局
圖1 展現圖1post
圖2 展現2測試
圖3 展現圖3spa
上邊三張展現圖,若是要說從理解難以成都來講,展現圖3是比較容易理解。下邊我就幾個須要注意的細節描述下:.net
餅圖繪製關鍵步驟:3d
首先來看兩個結構體,主要是用來緩存數據,PieItemPrivate存儲的是每個item項的內容,包括item的legend,文本、顏色、值和一些輔助的結構體;PieChartPrivate結構是餅圖類的私有數據存儲結構,具體含義看註釋code
1 struct PieItemPrivate 2 { 3 PieItem item;//用戶插入數據時的結構,包括註釋、值和顏色 4 QPainterPath path;//項繪製時區域 5 QPoint labelPos;//文本位置 6 QRect m_LegendRect;//legend的矩形 7 }; 8 9 struct PieChartPrivate 10 { 11 bool m_bLegendVisible = false;//是否顯示圖例 12 int m_Minx = 25;//左右最小邊距 13 int m_Miny = 25;//上下最小邊距 14 int m_MinDiameter = 130;//餅圖最小直徑 15 int m_RingWidth = 0;//若是是環,環的寬度 16 int m_StartRotationAngle = 0;//繪製item項的時候,其實角度 17 int m_LegendWidth = 100;//圖表寬度 能夠在插入新數據項的時候更新,計算展現legend所須要的最小尺寸 18 int m_LegendHeight = 30;//圖例高度 能夠在插入新數據項的時候更新,計算展現legend所須要的最小尺寸 19 double m_SumValue = 0;//全部item的value和 20 QRect m_PieRect;//餅圖繪製矩形 21 QColor m_LabelColor = QColor(0, 0, 0);//百分比文字顏色 22 QString m_RingLabel = QStringLiteral("餅圖");//圖表中心文字描述 23 QVector<PieItemPrivate> m_Items;//圖表項 24 };
一、當有新數據或者窗口大小發生變化時,計算數據緩存blog
1 void PieChart::ConstructData() 2 { 3 int pos = d_ptr->m_StartRotationAngle; 4 int angle; 5 QPainterPath subPath; 6 subPath.addEllipse(d_ptr->m_PieRect.adjusted(d_ptr->m_RingWidth, d_ptr->m_RingWidth, -d_ptr->m_RingWidth, -d_ptr->m_RingWidth)); 7 8 for (auto iter = d_ptr->m_Items.begin(); iter != d_ptr->m_Items.end(); ++iter) 9 { 10 angle = 16 * iter->item.value / d_ptr->m_SumValue * 360; 11 12 QPainterPath path; 13 path.moveTo(d_ptr->m_PieRect.center()); 14 path.arcTo(d_ptr->m_PieRect.x(), d_ptr->m_PieRect.y(), d_ptr->m_PieRect.width(), d_ptr->m_PieRect.height(), pos / 16.0, angle / 16.0); 15 path.closeSubpath(); 16 17 if (d_ptr->m_RingWidth > 0 && d_ptr->m_RingWidth <= d_ptr->m_PieRect.width() / 2) 18 { 19 path -= subPath; 20 } 21 22 iter->path = path; 23 24 double labelAngle = (pos + angle / 2) / 16; 25 double tx = (d_ptr->m_PieRect.width() - d_ptr->m_RingWidth) / 2 * qCos(labelAngle / 360 * 2 * 3.1415926); 26 double ty = -(d_ptr->m_PieRect.width() - d_ptr->m_RingWidth) / 2 * qSin(labelAngle / 360 * 2 * 3.1415926); 27 28 iter->labelPos = QPoint(tx, ty) + d_ptr->m_PieRect.center(); 29 30 pos += angle; 31 } 32 }
二、當窗口大小發生變化時,從新計算各項所在矩形,ConstructRect方式是用來計算各子項矩形區域的,內部調用ConstructCornerLayout方法是生產製定的佈局,有興趣的小夥伴能夠寫本身的矩形區域計算方式,開達到不一樣的繪製效果。接口
1 void PieChart::ConstructRect(const QSize & size) 2 { 3 switch (d_ptr->m_Items.size()) 4 { 5 case 4: 6 ConstructCornerLayout(size); 7 default: 8 break; 9 } 10 } 11 //該方法是針對4個legend,而且在四角的位置所計算的佈局方式,小夥伴也能夠實現本身的佈局計算,而後在ConstructRect接口中調用 12 void PieChart::ConstructCornerLayout(const QSize & size) 13 { 14 int currentR = d_ptr->m_MinDiameter; 15 int diameter; 16 int horiWidth = size.width(); 17 if (d_ptr->m_bLegendVisible) 18 { 19 horiWidth -= d_ptr->m_LegendWidth * 2; 20 } 21 22 if (horiWidth > size.height()) 23 { 24 diameter = size.height(); 25 } 26 else 27 { 28 diameter = horiWidth; 29 } 30 31 int x, y; 32 int r = diameter - d_ptr->m_Minx * 2; 33 currentR = r > currentR ? r : currentR; 34 if (d_ptr->m_bLegendVisible) 35 { 36 x = d_ptr->m_Minx + d_ptr->m_LegendWidth; 37 y = (size.height() - currentR) / 2; 38 //計算4個legend位置 39 d_ptr->m_Items[1].m_LegendRect = QRect(d_ptr->m_Minx, d_ptr->m_Miny, d_ptr->m_LegendWidth, d_ptr->m_LegendHeight); 40 d_ptr->m_Items[0].m_LegendRect = QRect(x + r, d_ptr->m_Miny, d_ptr->m_LegendWidth, d_ptr->m_LegendHeight); 41 d_ptr->m_Items[3].m_LegendRect = QRect(x + r, size.height() - d_ptr->m_Miny - 30, d_ptr->m_LegendWidth, d_ptr->m_LegendHeight); 42 d_ptr->m_Items[2].m_LegendRect = QRect(d_ptr->m_Minx, size.height() - d_ptr->m_Miny - 30, d_ptr->m_LegendWidth, d_ptr->m_LegendHeight); 43 } 44 else 45 { 46 x = d_ptr->m_Minx; 47 y = d_ptr->m_Miny; 48 } 49 50 d_ptr->m_PieRect = QRect(x, y, currentR, currentR);//計算餅圖位置 51 }
1 int main(int argc, char *argv[]) 2 { 3 QApplication a(argc, argv); 4 5 PieChart w; 6 w.AddData(100, Qt::red, "red"); 7 w.AddData(100, Qt::green, "green"); 8 w.AddData(100, Qt::blue, "blue"); 9 w.AddData(100, Qt::gray, "gray"); 10 w.show(); 11 12 return a.exec(); 13 }