• 关于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,本想忍痛升级吧,结果看到下图

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

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

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

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

    以上的函数合起来给我们的思路就是让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<QString,MP_VALUE>::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=fMaxVol<vol?vol:fMaxVol;
    19             fMinCur=fMinCur>cur?cur:fMinCur;
    20             fMaxCur=fMaxCur<cur?cur: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]+"<br/><span style='color:#1e96f4;'>电压值="+params[0].data[1]+"</span>" +
     43                 "<br/><span style='color:#fd4171;'>电流值="+params[1].data[1]+"</span>";
     44             }else {
     45                 if(params[0].seriesName=="单位:V"){
     46                     return "时间="+params[0].data[0]+"<br/><span style='color:#1e96f4;'>电压值="+params[0].data[1]+"</span>";
     47                 }else{
     48                     return "时间="+params[0].data[0]+"<br/><span style='color:#fd4171;'>电流值="+params[0].data[1]+"</span>";
     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                              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                              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<datas.length;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
  • 相关阅读:
    C++ STL Set使用
    C++ STL算法
    C++ STL List使用
    C++中的构造析构函数
    七、Linux进程调度-应用内核设置调度策略和优先级
    Qcom高通相关汇总
    Cgroup内核文档翻译(8)——/dev/cpuctl/*
    用户进程和内核线程的CPU亲和性设置
    Scheduler内核文档翻译(1)——Documentationschedulersched-tune.txt
    uCgui和emWin的区别
  • 原文地址:https://www.cnblogs.com/liushui-sky/p/7850759.html
Copyright © 2020-2023  润新知