关于qt QWebKit/QWebview 使用心得

当前项目为c/s客户端,采用qt4.8.7,需要使用仪表盘、折线图、柱状图等,曾经使用过qwt和自定义的图形控件,但是都不尽如人意。最近发现ECharts控件不错。为此就要在qt端使用web的技术。为此使用了QWebview的控件。关于它的使用网上有很多,一开始也没有深究,借鉴了前人的经验立即就使用了,而且也能正常使用。当时主要使用view->page()->mainFrame()->evaluateJavaScript这种方式。使用的形式是将需要显示的数据由qt主程序读取数据库,将返回的数据组成json格式的字符串传递给js执行。但是由于定时刷新频率较快1~5s,数据量较大(光数据就有172800~34560个)。所以导致程序内存增长很快。这是始料未及的,原以为qt的浏览器控件应该会像浏览器一样有垃圾回收,但是无奈,貌似没有或者不起作用,找了很久也没有相关资料。网上很多说早期的QWebKit存在内存泄漏、不完美、兼容性不好等诸多问题,看来是的了,毕竟早期qt团队貌似只是简单的应用,融合的不是特别好,尤其是4.8版本,好像5以后稍微好点(这些也就是网上道听途说的,是否为真,读者自判,o(* ̄︶ ̄*)o)。

于是乎就要解决这个内存持续增长的问题,网上既然如前面说QWebKit不是很好,qt5.6以后改为了QtWebEngine,本想忍痛升级吧,结果看到下图

关于qt QWebKit/QWebview 使用心得_第1张图片

居然mingw版不支持,好吧,这不改动太大了,还要装msvc版,算了,另寻它图吧。于是又回到QWebKit/QWebview ,看有没有好的方式。

在于做网页的同事交流后,试过各种的办法(有考虑是否可以加入定期垃圾回收,貌似不可行,在对QWebKit/QWebview运行机制不了解的情况下作罢,关于qt的书实在太少了,关于有介绍QWebKit/QWebview的书就更没有了)。

最终还是继续查看qt的帮助文档(类的介绍英文版),查到QWebFrame类中还有下面的函数(作用:把窗体对象给js用来调用。具体看help)

关于qt QWebKit/QWebview 使用心得_第2张图片

 

进而,查到void javaScriptWindowObjectCleared ()函数(作用:This signal is emitted whenever the global window object of the JavaScript environment is cleared, e.g., before starting a new load.)

关于qt QWebKit/QWebview 使用心得_第3张图片

以上的函数合起来给我们的思路就是让js来主动调用qt程序的对象。而evaluateJavaScript的模式是qt调用js。刚好两者有点类似互逆的形式。

这个网上有资料,搜索QT和JavaScript互调就会有资料,随便列出两份,读者可以自己看。

http://blog.csdn.net/b711183612/article/details/50593068

http://blog.csdn.net/allenjiao/article/details/44963131

以下是我项目中的应用,简单列点代码。

构造函数中:

1     connect(ui->webLine->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
2             this, SLOT(sltJavaScriptFromWinObject()));
3     ui->webLine->load(QUrl("file:///"+qApp->applicationDirPath()+"/Echart/page/commLineChart.html"));
4 
5     ui->webLine->settings()->setObjectCacheCapacities(0,0,0);
6 
7     connect(ui->webLine,SIGNAL(loadFinished(bool)),this,SLOT(sltInitial()));

槽函数:

void 类名::sltJavaScriptFromWinObject()
{
    ui->webLine->page()->mainFrame()->addToJavaScriptWindowObject("mywebkit",this);
}

js将要调用的函数(重点注意:这个函数必须是公共槽函数public slots:,注:其实根据其他文章说明“方法前需要Q_INVOKABLE修饰”,具体见参考。此外这里又有两种方式,1、getDataLine是由qt获得数据最后让js来直接获取数据字符串。2、其它两个函数则是直接让js调用获取数据的函数。最后证明内存的消耗是差不多的。但是1的使用需要js定时调用,qt主程序也要定期刷新数据(频率要比前者高),而2则直接在js中设置刷新频率即可,故在消耗差不多的前提下最终选择2方法)

1 public slots:
2     QString TestrefreshRTData();
3     QString TestrefreshLine();
4     QString getDataLine();
TestrefreshLine函数(包括cjson的使用):
 1 QString 类名::TestrefreshLine()
 2 {
 3         float fMinVol=qAbs(mpDataNHour.values().first().value(KEY_VOL));
 4         float fMaxVol=qAbs(mpDataNHour.values().first().value(KEY_VOL));
 5         float fMinCur=qAbs(mpDataNHour.values().first().value(KEY_CUR));
 6         float fMaxCur=qAbs(mpDataNHour.values().first().value(KEY_CUR));
 7         //先创建空对象
 8         cJSON *json = cJSON_CreateObject();
 9         cJSON *array=NULL;
10         cJSON_AddItemToObject(json,"commLineData",array=cJSON_CreateArray());
11         QMap::iterator it;
12         for ( it = mpDataNHour.begin(); it != mpDataNHour.end(); ++it )
13         {
14             QString datetime=it.key();
15             float vol=qAbs(it.value().value(KEY_VOL));
16             float cur=qAbs(it.value().value(KEY_CUR));
17             fMinVol=fMinVol>vol?vol:fMinVol;
18             fMaxVol=fMaxVolvol:fMaxVol;
19             fMinCur=fMinCur>cur?cur:fMinCur;
20             fMaxCur=fMaxCurcur:fMaxCur;
21             cJSON *obj=cJSON_CreateObject();
22             cJSON_AddItemToArray(array,obj);
23             cJSON_AddStringToObject(obj,"date",datetime.toStdString().c_str());
24             cJSON_AddStringToObject(obj,"vol",QString("%1").arg(vol).toStdString().c_str());
25             cJSON_AddStringToObject(obj,"cur",QString("%1").arg(cur).toStdString().c_str());
26         }
27 
28         fMinCur=fMinCur*(1-PROPORTION_CUR);
29         fMaxCur=fMaxCur*(1+PROPORTION_CUR);
30         fMinVol=fMinVol*(1-PROPORTION_VOL);
31         fMaxVol=fMaxVol*(1+PROPORTION_VOL);
32         cJSON_AddStringToObject(json,"minCur",QString::number(fMinCur, 'f', DECIMAL_CUR).toStdString().c_str());
33         cJSON_AddStringToObject(json,"maxCur",QString::number(fMaxCur, 'f', DECIMAL_CUR).toStdString().c_str());
34         cJSON_AddStringToObject(json,"minVol",QString::number(fMinVol, 'f', DECIMAL_VOL).toStdString().c_str());
35         cJSON_AddStringToObject(json,"maxVol",QString::number(fMaxVol, 'f', DECIMAL_VOL).toStdString().c_str());
36 
37         char *out=cJSON_Print(json); // json对象转字符串
38 
39         cJSON_Minify(out); // 去掉字符串中的换行和缩进
40         QString sz = QString(out);
41         free(out);//注意:这个千万别忘记,网上的很多人的资料把这个忘记了,造成内存泄漏
42         cJSON_Delete(json);
43 
44 /*********qt调用js,内存持续增长**********/
45 //        sz.replace(QRegExp("\""), "\\\"");
46 //        QString szValue = QString("optionData(\"%1\");").arg(sz);
47 //        ui->webLine->page()->mainFrame()->evaluateJavaScript(szValue);
48 
49 /***********js调用qt对象***************/
50         QString szValue = QString("%1").arg(sz);
51         return szValue;
52 //        return szValue.toStdString();//不用转换成string,QString可识别。
53 
54 }

js:

  1 //------------------------------------折线图-------------------------------------------------->
  2 $("#clc").css("width",window.innerWidth).css("height",window.innerHeight);
  3 
  4 //var lineChart=echarts.getInstanceByDom(document.getElementById("clc"));
  5 //echarts.dispose(lineChart);
  6 var lineChart = echarts.init(document.getElementById("clc"));
  7 var xData=[];
  8 var dyData=[];
  9 var dlData=[];
 10 var maxVol=10;
 11 var minVol=0;
 12 var maxCur=10;
 13 var minCur=0;
 14 var timeSplit=5;//时间间隔  每5秒执行一次
 15 
 16 var lineOption = {
 17     legend: {
 18         data:["单位:V","单位:A"],
 19         x:"center",
 20         y:"top",
 21         textStyle:{
 22             color:"#fff"
 23         },
 24         formatter: function (name) {
 25             if(name=="单位:V"){
 26                 return "电压";
 27             }else{
 28                 return "电流";
 29             }
 30         }
 31     },
 32     grid:{
 33         x:45,
 34         x2:45,
 35         y:45,
 36         y2:45
 37     },
 38     tooltip: {
 39         trigger: 'axis',
 40         formatter: function (params,ticket,callback) {
 41             if(params.length==2){
 42                 return "时间="+params[0].data[0]+"
电压值="+params[0].data[1]+"" + 43 "
电流值="+params[1].data[1]+""; 44 }else { 45 if(params[0].seriesName=="单位:V"){ 46 return "时间="+params[0].data[0]+"
电压值="+params[0].data[1]+""; 47 }else{ 48 return "时间="+params[0].data[0]+"
电流值="+params[0].data[1]+""; 49 } 50 } 51 52 53 }, 54 axisPointer: { 55 type: 'line' 56 } 57 }, 58 xAxis: [ 59 { 60 type: 'time',//#8296a2 61 show:true, 62 boundaryGap: false, 63 splitLine: { 64 show: false 65 }, 66 axisLine:{ 67 lineStyle:{ 68 color:"#fff" 69 } 70 }, 71 axisTick:{ 72 alignWithLabel:true 73 }, 74 splitNumber:30, 75 min:0, 76 max:0 77 //data:xData 78 } 79 ], 80 yAxis: [ 81 { 82 name:"单位:V", 83 nameTextStyle:{ 84 color:"#fff" 85 }, 86 type: 'value', 87 splitLine: { 88 show: true, 89 lineStyle:{ 90 color:"#5c6f85" 91 } 92 }, 93 position:"left", 94 axisLine:{ 95 lineStyle:{ 96 color:"#fff" 97 } 98 }, 99 min:minVol, 100 max:maxVol 101 }, 102 { 103 name:"单位:A", 104 nameTextStyle:{ 105 color:"#fff" 106 }, 107 nameLocation:"end", 108 type: 'value', 109 position:"right", 110 boundaryGap: [0, '100%'], 111 splitLine: { 112 show: false, 113 }, 114 position:"right", 115 axisLine:{ 116 lineStyle:{ 117 color:"#fff" 118 } 119 }, 120 min:minCur, 121 max:maxCur 122 } 123 ], 124 series: [ 125 { 126 name:"单位:V", 127 type: 'line', 128 smooth: true, 129 showSymbol: false, 130 hoverAnimation: false, 131 itemStyle:{ 132 normal:{ 133 color:"#1e96f4", 134 lineStyle: { 135 width: 1, 136 } 137 } 138 }, 139 data: dyData 140 141 } , 142 { 143 name:"单位:A", 144 yAxisIndex:1, 145 type: 'line', 146 smooth: true, 147 showSymbol: false, 148 hoverAnimation: false, 149 itemStyle:{ 150 normal:{ 151 color:"#fd4171", 152 lineStyle: { 153 width: 1, 154 } 155 } 156 }, 157 data: dlData 158 } 159 160 ] 161 }; 162 //lineChart.setOption(lineOption); 163 164 function optionData(obj){ 165 var json=$.parseJSON(obj.toString()); 166 minVol=parseFloat(json.minVol); 167 maxVol=parseFloat(json.maxVol); 168 minCur=parseFloat(json.minCur); 169 maxCur=parseFloat(json.maxCur); 170 var startDate=json.startDate; 171 var endDate=json.endDate; 172 173 dyData=[]; 174 dlData=[]; 175 datas=json.commLineData; 176 for(var i=0;i){ 177 var vol=datas[i].vol; 178 var cur=datas[i].cur; 179 var dateTime=datas[i].date; 180 var volArr=[dateTime,vol]; 181 var curArr=[dateTime,cur]; 182 dyData.push(volArr); 183 dlData.push(curArr); 184 } 185 186 if(datas.length==0){ 187 188 lineOption.xAxis[0].show=false; 189 } 190 lineOption.xAxis[0].min=startDate; 191 lineOption.xAxis[0].max=endDate; 192 //lineOption.xAxis[0].data=xData; 193 lineOption.yAxis[0].min=minVol; 194 lineOption.yAxis[0].max=maxVol; 195 lineOption.yAxis[1].min=minCur; 196 lineOption.yAxis[1].max=maxCur; 197 lineOption.series[0].data=dyData; 198 lineOption.series[1].data=dlData; 199 //lineChart.setOption(lineOption); 200 lineChart.setOption(lineOption); 201 } 202 203 204 function reset(){ 205 lineOption.series[0].data=[]; 206 lineOption.series[1].data=[]; 207 lineChart.setOption(lineOption); 208 } 209 210 211 function setBorder(width,height){ 212 $("#clc").css("width",width+"px").css("height",height+"px"); 213 $(lineChart).resize(); 214 } 215 216 217 /*****js调用qt对象,调试时可以加入try...catch...捕获错误***/ 218 $(function(){ 219 var jsonObj=window.mywebkit.refreshRTData(); 220 optionData(obj); 221 setInterval(function(){ 222 jsonObj=window.mywebkit.refreshRTData(); 223 optionData(obj); 224 },timeSplit*1000); 225 }); 226 227 /*$(function(){ 228 try{ 229 // alert("start"); 230 setInterval(function(){ 231 try{ 232 var obj=window.mywebkit.getDataLine(); 233 // alert(obj); 234 optionData(obj); 235 } 236 catch(e) 237 { 238 alert("Error_2!"); 239 } 240 },5000); 241 // alert("ok"); 242 } 243 catch(e) { 244 alert("Error_1!"); 245 } 246 });*/

最后分别列出qt调用js、js调用qt对象的内存比较数据。

 qt调用js内存情况如下:

2017-11-7 
107268KB    13:10 (开始运行) 
200852KB    15:33

102888KB    2017-11-7 17:31(对远程QT客户端重启后开始运行)
138712KB    2017-11-8 08:37
451120KB    2017-11-8 17:08
538248KB    2017-11-9 09:56
连续运行后,内存持续增长425.16M

js调用qt对象内存情况(启动后会有一段时间的增长(10分钟内),包括鼠标在图形上操作会增长到60M多,之后稳定,没有持续增长,成功):

1方法:
55600KB    2017-11-16 16:57 
61056KB    2017-11-17 08:11  稳定在这个范围
2方法:
46588KB    2017-11-16 17:07  
61064KB    2017-11-17 08:11  稳定在这个范围

参考:http://www.cnblogs.com/liushui-sky/p/7851654.html

你可能感兴趣的:(javascript,c/c++,json)