当前位置:   article > 正文

qml 动态创建复杂饼图_怎么使qml 中显示饼状图的占比

怎么使qml 中显示饼状图的占比

数据的展示自然离不开图表,qt默认安装没有将QtCharts模块集成并社区版中,导致只能自己编译或使用第三方图库,如chartDirector或qwtplot等等。

本次介绍Qt在qml中使用QtCharts绘制稍复杂的饼图示例,并且该饼图提供一个接口传入数据并非一个简单的demo程序。

首先在安装Qt时要选中QtCharts模块,这点就不介绍了。

先来看一下效果


中间为第一环绘制了第一层的数据比例,第二层是以第一层为基础,将第一层的继续分比例显示。这里我们先来熟悉一下画饼图的控件

  1. PieSeries{
  2. startAngle: 起始角度
  3. endAngle: 终止角度
  4. holeSize: 内狐离圆心的距离
  5. size: 外狐离圆心的距离
  6. }
以上只列举了本次博客用到的主要属性,如果还想了解其它属性请查看Qt帮助文档。下一个控件是PieSlice
  1. PieSlice{
  2. angleSpan: 狐所占角度
  3. labelVisible: 是否显示标签
  4. label: 标签显示内容
  5. value: 狐所代表的值
  6. }
知道以上两个控件后,我们大概可以知道,饼图是由扇形组成的,而要想出现环状效果,只要使扇形内儿离圆心的距离大于0,且外儿离圆心的距离
大于内狐离圆心的距离就可以了。所以我们 可以构想出上图的思路,在一个ChartView中放一个PieSeries画里面的一圈,这个PieSeies里有两PieSlice;
设置它的startAngle =0, endAngle=360;里面一圈就画好了。接着在ChartView中再放一个PieSeries用来画网银止付的外环,这个PieSeries的起始角度为statAngle=0,
终止角度为endAngle= "网银止付的slice对象".angleSpan,内狐离圆心的距离为最里环的外狐离圆心的距离,由于最里的一环没有设置Size(默认为0.7),所以这一个PieSeries
的holeSize=0.7,外狐离圆心的距离比0.7大就可以。这里我取了size=0.8;第二个PieSeries就画好了。最后一个原理和第二个一样。我们的代码可以是下面这样
  1. ChartView{
  2. id: chartView
  3. title: "2017-05-12 至 2017-08-29电信诈骗统计饼图"
  4. anchors.fill: parent
  5. legend.alignment: Qt.AlignRight
  6. antialiasing: true
  7. animationOptions: ChartView.AllAnimations
  8. property real sumAngle: 0
  9. PieSeries{
  10. PieSlice{
  11. id: sliceBank
  12. labelVisible: true
  13. labelPosition: PieSlice.LabelInsideHorizontal
  14. label: qsTr("网银止付 ") + (new Array(2).join('0') + percentage * 100).slice(-2) + "%"
  15. value: pieBankSeries.sum
  16. }
  17. PieSlice{
  18. id: sliceCall
  19. labelVisible: true
  20. labelPosition: PieSlice.LabelInsideHorizontal
  21. label: qsTr("智能追呼 ") + (new Array(2).join('0') + percentage * 100).slice(-2) + "%"
  22. value: pieCallSeries.sum
  23. }
  24. }
  25. PieSeries{
  26. id: pieBankSeries
  27. size: 0.8
  28. holeSize: 0.7
  29. startAngle: 0
  30. endAngle: sliceBank.angleSpan
  31. PieSlice{
  32. labelVisible: true
  33. label: qsTr("中国银行")
  34. value: 120
  35. }
  36. PieSlice{
  37. labelVisible: true
  38. label: qsTr("工商银行")
  39. value: 130
  40. }
  41. PieSlice{
  42. labelVisible: true
  43. label: qsTr("招商银行")
  44. value: 142
  45. }
  46. }
  47. PieSeries{
  48. id: pieCallSeries
  49. size: 0.8
  50. holeSize: 0.7
  51. startAngle: sliceBank.angleSpan
  52. endAngle: 360
  53. PieSlice{
  54. labelVisible: true
  55. label: qsTr("中国电信")
  56. value: 123
  57. }
  58. PieSlice{
  59. labelVisible: true
  60. label: qsTr("中国联通")
  61. value: 98
  62. }
  63. PieSlice{
  64. labelVisible: true
  65. label: qsTr("中国移动")
  66. value: 400
  67. }
  68. }
  69. }
像上面这样我们便可以画出上图一样的饼图,但是这样很明显,饼图的数据很死,能表示的数据也有限。所以我们应该把它做成接口。
这里我先用了json做为数据的接口,给出上面图的数据如下
  1. [{model: "网银止付",data: [{label: "招商银行",total_count: 115},
  2. {label: "工商银行",total_count: 200},
  3. {label: "中国银行",total_count: 220}]},
  4. {model: "智能追呼",data: [{label: "中国移动",total_count: 100},
  5. {label: "中国联通",total_count: 89},
  6. {label: "中国电信",total_count: 400}]}]
解析数据的方法因人而异,这里我分成了两步,一是写了一个画饼图的方法,二是写了一个解析json并调用画饼图的方法的方法。
画饼图的方法如下
  1. function createPieSeries(pieArgObj){
  2. var str = "import QtQuick 2.7;import QtCharts 2.0;PieSeries{}";
  3. var pieSeriesObj = Qt.createQmlObject(str,chartView,"dynamicSnippet1"); //创建一个PieSeries以chartView为父对象
  4. pieSeriesObj.startAngle = pieArgObj.startAngle; //起始角度
  5. pieSeriesObj.endAngle = pieArgObj.endAngle; //终止角度
  6. var dataArray = pieArgObj.data;
  7. var dataCount = dataArray.length;
  8. for(var i=0;i<dataCount;i++){
  9. var sliceObj = pieSeriesObj.append(dataArray[i].label,dataArray[i].total_count); //通过PieSeries的append方法添加PieSlice
  10. sliceObj.labelVisible = true; //设置PieSlice的标签可见
  11. sliceObj.label = dataArray[i].label; //设置PieSlice的标签内容
  12. }
  13. if(pieArgObj.position == 0){ //0代表是内环,此时显示百分比
  14. var sliceCount = pieSeriesObj.count;
  15. for(var j =0; j<sliceCount;j++){
  16. sliceObj = pieSeriesObj.at(j);
  17. sliceObj.labelPosition = PieSlice.LabelInsideHorizontal //设置PieSlice的label显示位置
  18. sliceObj.label = sliceObj.label + " " + (new Array(2).join('0') + sliceObj.percentage * 100).slice(-2) + "%"; //保留两位小数,并以百
  19. } //分比显示
  20. }
  21. return pieSeriesObj;
  22. }
解析数据的方法如下
  1. function loadData(jsObj){
  2. if(!(jsObj instanceof Array)){ //如果不是array,直接返回
  3. console.log("errror argument!")
  4. return;
  5. }
  6. var dataLength = jsObj.length;
  7. var modelArray = new Array();
  8. var modelObject = new Object();
  9. for(var i=0;i<dataLength;i++){ //获取网银止付和智能追呼的总值,通过计算子块的和;
  10. var nodeData = jsObj[i];
  11. var nodeDataArray = nodeData.data;
  12. var nodeDataArrayLength = nodeDataArray.length;
  13. var pieSeriesSumValue = 0
  14. for(var j=0;j<nodeDataArrayLength;j++){
  15. pieSeriesSumValue += nodeDataArray[j].total_count;
  16. }
  17. modelArray[i] = {label: nodeData.model,total_count: pieSeriesSumValue};
  18. }
  19. var obj = createPieSeries({startAngle:0,endAngle:360,data: modelArray,position: 0}); //先创建最里环
  20. var endAngle = new Number();
  21. for(var j=0;j<dataLength;j++){
  22. var curAngle = obj.at(j).angleSpan; //
  23. endAngle += curAngle;
  24. var subObj = createPieSeries({startAngle: endAngle - curAngle,endAngle: endAngle,data: jsObj[j].data,position: 1}); //statAngle为最里环
  1. subObj.holeSize = 0.7; //的每个PieSlice的angleSpan之各减去第二环当前的角度,endAngle为最里环每个PieSlice的angleSpan和
  2. subObj.size = 0.8; //设置内狐和外狐离圆心的距离。
  3. }
  4. }

上面我做的这个接口只能表示两环,表示的数据块理论上是无限个,这样我们就可以传入数据动态创建了。贴一个完整代码。
  1. import QtQuick 2.8
  2. import QtCharts 2.0
  3. import QtQuick.Window 2.2
  4. Window {
  5. visible: true
  6. width: 640
  7. height: 480
  8. title: qsTr("Hello World")
  9. Item {
  10. anchors.fill: parent
  11. ChartView{
  12. id: chartView
  13. title: "2017-05-12 至 2017-08-29电信诈骗统计饼图"
  14. anchors.fill: parent
  15. legend.alignment: Qt.AlignRight
  16. antialiasing: true
  17. animationOptions: ChartView.AllAnimations
  18. property real sumAngle: 0
  19. }
  20. function createPieSeries(pieArgObj){
  21. var str = "import QtQuick 2.7;import QtCharts 2.0;PieSeries{}";
  22. var pieSeriesObj = Qt.createQmlObject(str,chartView,"dynamicSnippet1");
  23. pieSeriesObj.startAngle = pieArgObj.startAngle;
  24. pieSeriesObj.endAngle = pieArgObj.endAngle;
  25. var dataArray = pieArgObj.data;
  26. var dataCount = dataArray.length;
  27. for(var i=0;i<dataCount;i++){
  28. var sliceObj = pieSeriesObj.append(dataArray[i].label,dataArray[i].total_count);
  29. sliceObj.labelVisible = true;
  30. sliceObj.label = dataArray[i].label;
  31. }
  32. if(pieArgObj.position == 0){
  33. var sliceCount = pieSeriesObj.count;
  34. for(var j =0; j<sliceCount;j++){
  35. sliceObj = pieSeriesObj.at(j);
  36. sliceObj.labelPosition = PieSlice.LabelInsideHorizontal
  37. sliceObj.label = sliceObj.label + " " + (new Array(2).join('0') + sliceObj.percentage * 100).slice(-2) + "%";
  38. }
  39. }
  40. return pieSeriesObj;
  41. }
  42. function loadData(jsObj){
  43. if(!(jsObj instanceof Array)){
  44. console.log("errror argument!")
  45. return;
  46. }
  47. var dataLength = jsObj.length;
  48. var modelArray = new Array();
  49. var modelObject = new Object();
  50. for(var i=0;i<dataLength;i++){
  51. var nodeData = jsObj[i];
  52. var nodeDataArray = nodeData.data;
  53. var nodeDataArrayLength = nodeDataArray.length;
  54. var pieSeriesSumValue = 0
  55. for(var j=0;j<nodeDataArrayLength;j++){
  56. pieSeriesSumValue += nodeDataArray[j].total_count;
  57. }
  58. modelArray[i] = {label: nodeData.model,total_count: pieSeriesSumValue};
  59. }
  60. var obj = createPieSeries({startAngle:0,endAngle:360,data: modelArray,position: 0});
  61. var endAngle = new Number();
  62. for(var j=0;j<dataLength;j++){
  63. var curAngle = obj.at(j).angleSpan;
  64. endAngle += curAngle;
  65. var subObj = createPieSeries({startAngle: endAngle - curAngle,endAngle: endAngle,data: jsObj[j].data,position: 1});
  66. subObj.holeSize = 0.7;
  67. subObj.size = 0.8;
  68. }
  69. }
  70. Component.onCompleted: loadData([{model: "网银止付",data: [{label: "招商银行",total_count: 115},
  71. {label: "工商银行",total_count: 200},
  72. {label: "中国银行",total_count: 220}]},
  73. {model: "智能追呼",data: [{label: "中国移动",total_count: 100},
  74. {label: "中国联通",total_count: 89},
  75. {label: "中国电信",total_count: 400}]}])
  76. }
  77. }
这个结果就是最顶上的饼图,我修改数据如下之后
  1. Component.onCompleted: loadData([{model: "网银止付",data: [{label: "招商银行",total_count: 115},
  2. {label: "工商银行",total_count: 200},
  3. {label: "中国银行",total_count: 220}]},
  4. {model: "智能追呼",data: [{label: "中国移动",total_count: 100},
  5. {label: "中国联通",total_count: 89},
  6. {label: "中国电信",total_count: 400}]},
  7. {model: "其它",data: [{label: "报纸",total_count: 100},
  8. {label: "杂志",total_count: 89},
  9. {label: "书刊",total_count: 98}]}])

结果为

到此结束,祝大家工作愉快。



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/寸_铁/article/detail/924978
推荐阅读
相关标签
  

闽ICP备14008679号