qml 动态创建复杂饼图
来源:互联网 发布:java编译执行命令 编辑:程序博客网 时间:2024/05/14 20:16
数据的展示自然离不开图表,qt默认安装没有将QtCharts模块集成并社区版中,导致只能自己编译或使用第三方图库,如chartDirector或qwtplot等等。
本次介绍Qt在qml中使用QtCharts绘制稍复杂的饼图示例,并且该饼图提供一个接口传入数据并非一个简单的demo程序。
首先在安装Qt时要选中QtCharts模块,这点就不介绍了。
先来看一下效果
中间为第一环绘制了第一层的数据比例,第二层是以第一层为基础,将第一层的继续分比例显示。这里我们先来熟悉一下画饼图的控件
PieSeries{ startAngle: 起始角度 endAngle: 终止角度 holeSize: 内狐离圆心的距离 size: 外狐离圆心的距离}以上只列举了本次博客用到的主要属性,如果还想了解其它属性请查看Qt帮助文档。下一个控件是PieSlice
PieSlice{ angleSpan: 狐所占角度 labelVisible: 是否显示标签 label: 标签显示内容 value: 狐所代表的值}知道以上两个控件后,我们大概可以知道,饼图是由扇形组成的,而要想出现环状效果,只要使扇形内儿离圆心的距离大于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就画好了。最后一个原理和第二个一样。我们的代码可以是下面这样
ChartView{ id: chartView title: "2017-05-12 至 2017-08-29电信诈骗统计饼图" anchors.fill: parent legend.alignment: Qt.AlignRight antialiasing: true animationOptions: ChartView.AllAnimations property real sumAngle: 0 PieSeries{ PieSlice{ id: sliceBank labelVisible: true labelPosition: PieSlice.LabelInsideHorizontal label: qsTr("网银止付 ") + (new Array(2).join('0') + percentage * 100).slice(-2) + "%" value: pieBankSeries.sum } PieSlice{ id: sliceCall labelVisible: true labelPosition: PieSlice.LabelInsideHorizontal label: qsTr("智能追呼 ") + (new Array(2).join('0') + percentage * 100).slice(-2) + "%" value: pieCallSeries.sum } } PieSeries{ id: pieBankSeries size: 0.8 holeSize: 0.7 startAngle: 0 endAngle: sliceBank.angleSpan PieSlice{ labelVisible: true label: qsTr("中国银行") value: 120 } PieSlice{ labelVisible: true label: qsTr("工商银行") value: 130 } PieSlice{ labelVisible: true label: qsTr("招商银行") value: 142 } } PieSeries{ id: pieCallSeries size: 0.8 holeSize: 0.7 startAngle: sliceBank.angleSpan endAngle: 360 PieSlice{ labelVisible: true label: qsTr("中国电信") value: 123 } PieSlice{ labelVisible: true label: qsTr("中国联通") value: 98 } PieSlice{ labelVisible: true label: qsTr("中国移动") value: 400 } } }像上面这样我们便可以画出上图一样的饼图,但是这样很明显,饼图的数据很死,能表示的数据也有限。所以我们应该把它做成接口。
这里我先用了json做为数据的接口,给出上面图的数据如下
[{model: "网银止付",data: [{label: "招商银行",total_count: 115}, {label: "工商银行",total_count: 200}, {label: "中国银行",total_count: 220}]}, {model: "智能追呼",data: [{label: "中国移动",total_count: 100}, {label: "中国联通",total_count: 89}, {label: "中国电信",total_count: 400}]}]解析数据的方法因人而异,这里我分成了两步,一是写了一个画饼图的方法,二是写了一个解析json并调用画饼图的方法的方法。
画饼图的方法如下
function createPieSeries(pieArgObj){ var str = "import QtQuick 2.7;import QtCharts 2.0;PieSeries{}"; var pieSeriesObj = Qt.createQmlObject(str,chartView,"dynamicSnippet1"); //创建一个PieSeries以chartView为父对象 pieSeriesObj.startAngle = pieArgObj.startAngle; //起始角度 pieSeriesObj.endAngle = pieArgObj.endAngle; //终止角度 var dataArray = pieArgObj.data; var dataCount = dataArray.length; for(var i=0;i<dataCount;i++){ var sliceObj = pieSeriesObj.append(dataArray[i].label,dataArray[i].total_count); //通过PieSeries的append方法添加PieSlice sliceObj.labelVisible = true; //设置PieSlice的标签可见 sliceObj.label = dataArray[i].label; //设置PieSlice的标签内容 } if(pieArgObj.position == 0){ //0代表是内环,此时显示百分比 var sliceCount = pieSeriesObj.count; for(var j =0; j<sliceCount;j++){ sliceObj = pieSeriesObj.at(j); sliceObj.labelPosition = PieSlice.LabelInsideHorizontal //设置PieSlice的label显示位置 sliceObj.label = sliceObj.label + " " + (new Array(2).join('0') + sliceObj.percentage * 100).slice(-2) + "%"; //保留两位小数,并以百 } //分比显示 } return pieSeriesObj; }解析数据的方法如下
function loadData(jsObj){ if(!(jsObj instanceof Array)){ //如果不是array,直接返回 console.log("errror argument!") return; } var dataLength = jsObj.length; var modelArray = new Array(); var modelObject = new Object(); for(var i=0;i<dataLength;i++){ //获取网银止付和智能追呼的总值,通过计算子块的和; var nodeData = jsObj[i]; var nodeDataArray = nodeData.data; var nodeDataArrayLength = nodeDataArray.length; var pieSeriesSumValue = 0 for(var j=0;j<nodeDataArrayLength;j++){ pieSeriesSumValue += nodeDataArray[j].total_count; } modelArray[i] = {label: nodeData.model,total_count: pieSeriesSumValue}; } var obj = createPieSeries({startAngle:0,endAngle:360,data: modelArray,position: 0}); //先创建最里环 var endAngle = new Number(); for(var j=0;j<dataLength;j++){ var curAngle = obj.at(j).angleSpan; // endAngle += curAngle; var subObj = createPieSeries({startAngle: endAngle - curAngle,endAngle: endAngle,data: jsObj[j].data,position: 1}); //statAngle为最里环
subObj.holeSize = 0.7; //的每个PieSlice的angleSpan之各减去第二环当前的角度,endAngle为最里环每个PieSlice的angleSpan和 subObj.size = 0.8; //设置内狐和外狐离圆心的距离。 } }
上面我做的这个接口只能表示两环,表示的数据块理论上是无限个,这样我们就可以传入数据动态创建了。贴一个完整代码。
import QtQuick 2.8import QtCharts 2.0import QtQuick.Window 2.2Window { visible: true width: 640 height: 480 title: qsTr("Hello World") Item { anchors.fill: parent ChartView{ id: chartView title: "2017-05-12 至 2017-08-29电信诈骗统计饼图" anchors.fill: parent legend.alignment: Qt.AlignRight antialiasing: true animationOptions: ChartView.AllAnimations property real sumAngle: 0 } function createPieSeries(pieArgObj){ var str = "import QtQuick 2.7;import QtCharts 2.0;PieSeries{}"; var pieSeriesObj = Qt.createQmlObject(str,chartView,"dynamicSnippet1"); pieSeriesObj.startAngle = pieArgObj.startAngle; pieSeriesObj.endAngle = pieArgObj.endAngle; var dataArray = pieArgObj.data; var dataCount = dataArray.length; for(var i=0;i<dataCount;i++){ var sliceObj = pieSeriesObj.append(dataArray[i].label,dataArray[i].total_count); sliceObj.labelVisible = true; sliceObj.label = dataArray[i].label; } if(pieArgObj.position == 0){ var sliceCount = pieSeriesObj.count; for(var j =0; j<sliceCount;j++){ sliceObj = pieSeriesObj.at(j); sliceObj.labelPosition = PieSlice.LabelInsideHorizontal sliceObj.label = sliceObj.label + " " + (new Array(2).join('0') + sliceObj.percentage * 100).slice(-2) + "%"; } } return pieSeriesObj; } function loadData(jsObj){ if(!(jsObj instanceof Array)){ console.log("errror argument!") return; } var dataLength = jsObj.length; var modelArray = new Array(); var modelObject = new Object(); for(var i=0;i<dataLength;i++){ var nodeData = jsObj[i]; var nodeDataArray = nodeData.data; var nodeDataArrayLength = nodeDataArray.length; var pieSeriesSumValue = 0 for(var j=0;j<nodeDataArrayLength;j++){ pieSeriesSumValue += nodeDataArray[j].total_count; } modelArray[i] = {label: nodeData.model,total_count: pieSeriesSumValue}; } var obj = createPieSeries({startAngle:0,endAngle:360,data: modelArray,position: 0}); var endAngle = new Number(); for(var j=0;j<dataLength;j++){ var curAngle = obj.at(j).angleSpan; endAngle += curAngle; var subObj = createPieSeries({startAngle: endAngle - curAngle,endAngle: endAngle,data: jsObj[j].data,position: 1}); subObj.holeSize = 0.7; subObj.size = 0.8; } } Component.onCompleted: loadData([{model: "网银止付",data: [{label: "招商银行",total_count: 115}, {label: "工商银行",total_count: 200}, {label: "中国银行",total_count: 220}]}, {model: "智能追呼",data: [{label: "中国移动",total_count: 100}, {label: "中国联通",total_count: 89}, {label: "中国电信",total_count: 400}]}]) }}这个结果就是最顶上的饼图,我修改数据如下之后
Component.onCompleted: loadData([{model: "网银止付",data: [{label: "招商银行",total_count: 115}, {label: "工商银行",total_count: 200}, {label: "中国银行",total_count: 220}]}, {model: "智能追呼",data: [{label: "中国移动",total_count: 100}, {label: "中国联通",total_count: 89}, {label: "中国电信",total_count: 400}]}, {model: "其它",data: [{label: "报纸",total_count: 100}, {label: "杂志",total_count: 89}, {label: "书刊",total_count: 98}]}])
结果为
到此结束,祝大家工作愉快。
阅读全文
0 0
- qml 动态创建复杂饼图
- 动态创建qml
- qml 动态创建TableView
- QML如何创建动态组件
- Qml TabView 如何动态创建Tab
- qml之动态创建销毁对象
- qml学习-------------使用Loader动态创建和删除组件
- qml 动态创建的FileDialog程序异常问题
- qt qml c++ 画动态折线图
- 使用Qml创建各种list(二)创建一个简单的动态列表
- QML - 动态柱状图
- Qml动态语言切换
- QML之动态加载
- 用QML创建 QQuickWindow
- QML工程创建
- QML简单动画Behavior代替复杂代码
- QML之动态菜单配置
- 为QML动态生成Tab
- java自定义工具类
- OpenGL控制台项目只显示Windows窗口
- Django——模板总结
- spring配置hibernate添加数据save not allow in read-only mode
- 经典的几个卷积神经网络(基本网络)
- qml 动态创建复杂饼图
- 基于卷积神经网络的目标检测算法
- 140. Word Break II
- 【OD】简单使用
- 二叉查找树
- 机器学习之神经网络(Question和Answer)
- 幼儿园第五天
- python学习之列表的使用
- 素数距离