当前项目为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

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

构造函数中:

     connect(ui->webLine->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
this, SLOT(sltJavaScriptFromWinObject()));
ui->webLine->load(QUrl("file:///"+qApp->applicationDirPath()+"/Echart/page/commLineChart.html")); ui->webLine->settings()->setObjectCacheCapacities(,,); 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方法)

 public slots:
QString TestrefreshRTData();
QString TestrefreshLine();
QString getDataLine();
TestrefreshLine函数(包括cjson的使用):
 QString 类名::TestrefreshLine()
{
float fMinVol=qAbs(mpDataNHour.values().first().value(KEY_VOL));
float fMaxVol=qAbs(mpDataNHour.values().first().value(KEY_VOL));
float fMinCur=qAbs(mpDataNHour.values().first().value(KEY_CUR));
float fMaxCur=qAbs(mpDataNHour.values().first().value(KEY_CUR));
//先创建空对象
cJSON *json = cJSON_CreateObject();
cJSON *array=NULL;
cJSON_AddItemToObject(json,"commLineData",array=cJSON_CreateArray());
QMap<QString,MP_VALUE>::iterator it;
for ( it = mpDataNHour.begin(); it != mpDataNHour.end(); ++it )
{
QString datetime=it.key();
float vol=qAbs(it.value().value(KEY_VOL));
float cur=qAbs(it.value().value(KEY_CUR));
fMinVol=fMinVol>vol?vol:fMinVol;
fMaxVol=fMaxVol<vol?vol:fMaxVol;
fMinCur=fMinCur>cur?cur:fMinCur;
fMaxCur=fMaxCur<cur?cur:fMaxCur;
cJSON *obj=cJSON_CreateObject();
cJSON_AddItemToArray(array,obj);
cJSON_AddStringToObject(obj,"date",datetime.toStdString().c_str());
cJSON_AddStringToObject(obj,"vol",QString("%1").arg(vol).toStdString().c_str());
cJSON_AddStringToObject(obj,"cur",QString("%1").arg(cur).toStdString().c_str());
} fMinCur=fMinCur*(-PROPORTION_CUR);
fMaxCur=fMaxCur*(+PROPORTION_CUR);
fMinVol=fMinVol*(-PROPORTION_VOL);
fMaxVol=fMaxVol*(+PROPORTION_VOL);
cJSON_AddStringToObject(json,"minCur",QString::number(fMinCur, 'f', DECIMAL_CUR).toStdString().c_str());
cJSON_AddStringToObject(json,"maxCur",QString::number(fMaxCur, 'f', DECIMAL_CUR).toStdString().c_str());
cJSON_AddStringToObject(json,"minVol",QString::number(fMinVol, 'f', DECIMAL_VOL).toStdString().c_str());
cJSON_AddStringToObject(json,"maxVol",QString::number(fMaxVol, 'f', DECIMAL_VOL).toStdString().c_str()); char *out=cJSON_Print(json); // json对象转字符串 cJSON_Minify(out); // 去掉字符串中的换行和缩进
QString sz = QString(out);
free(out);//注意:这个千万别忘记,网上的很多人的资料把这个忘记了,造成内存泄漏
cJSON_Delete(json); /*********qt调用js,内存持续增长**********/
// sz.replace(QRegExp("\""), "\\\"");
// QString szValue = QString("optionData(\"%1\");").arg(sz);
// ui->webLine->page()->mainFrame()->evaluateJavaScript(szValue); /***********js调用qt对象***************/
QString szValue = QString("%1").arg(sz);
return szValue;
// return szValue.toStdString();//不用转换成string,QString可识别。 }

js:

 //------------------------------------折线图-------------------------------------------------->
$("#clc").css("width",window.innerWidth).css("height",window.innerHeight); //var lineChart=echarts.getInstanceByDom(document.getElementById("clc"));
//echarts.dispose(lineChart);
var lineChart = echarts.init(document.getElementById("clc"));
var xData=[];
var dyData=[];
var dlData=[];
var maxVol=10;
var minVol=0;
var maxCur=10;
var minCur=0;
var timeSplit=5;//时间间隔 每5秒执行一次 var lineOption = {
legend: {
data:["单位:V","单位:A"],
x:"center",
y:"top",
textStyle:{
color:"#fff"
},
formatter: function (name) {
if(name=="单位:V"){
return "电压";
}else{
return "电流";
}
}
},
grid:{
x:45,
x2:45,
y:45,
y2:45
},
tooltip: {
trigger: 'axis',
formatter: function (params,ticket,callback) {
if(params.length==2){
return "时间="+params[0].data[0]+"<br/><span style='color:#1e96f4;'>电压值="+params[0].data[1]+"</span>" +
"<br/><span style='color:#fd4171;'>电流值="+params[1].data[1]+"</span>";
}else {
if(params[0].seriesName=="单位:V"){
return "时间="+params[0].data[0]+"<br/><span style='color:#1e96f4;'>电压值="+params[0].data[1]+"</span>";
}else{
return "时间="+params[0].data[0]+"<br/><span style='color:#fd4171;'>电流值="+params[0].data[1]+"</span>";
}
} },
axisPointer: {
type: 'line'
}
},
xAxis: [
{
type: 'time',//#8296a2
show:true,
boundaryGap: false,
splitLine: {
show: false
},
axisLine:{
lineStyle:{
color:"#fff"
}
},
axisTick:{
alignWithLabel:true
},
splitNumber:30,
min:0,
max:0
//data:xData
}
],
yAxis: [
{
name:"单位:V",
nameTextStyle:{
color:"#fff"
},
type: 'value',
splitLine: {
show: true,
lineStyle:{
color:"#5c6f85"
}
},
position:"left",
axisLine:{
lineStyle:{
color:"#fff"
}
},
min:minVol,
max:maxVol
},
{
name:"单位:A",
nameTextStyle:{
color:"#fff"
},
nameLocation:"end",
type: 'value',
position:"right",
boundaryGap: [0, '100%'],
splitLine: {
show: false,
},
position:"right",
axisLine:{
lineStyle:{
color:"#fff"
}
},
min:minCur,
max:maxCur
}
],
series: [
{
name:"单位:V",
type: 'line',
smooth: true,
showSymbol: false,
hoverAnimation: false,
itemStyle:{
normal:{
color:"#1e96f4",
lineStyle: {
width: 1,
}
}
},
data: dyData } ,
{
name:"单位:A",
yAxisIndex:1,
type: 'line',
smooth: true,
showSymbol: false,
hoverAnimation: false,
itemStyle:{
normal:{
color:"#fd4171",
lineStyle: {
width: 1,
}
}
},
data: dlData
} ]
};
//lineChart.setOption(lineOption); function optionData(obj){
var json=$.parseJSON(obj.toString());
minVol=parseFloat(json.minVol);
maxVol=parseFloat(json.maxVol);
minCur=parseFloat(json.minCur);
maxCur=parseFloat(json.maxCur);
var startDate=json.startDate;
var endDate=json.endDate; dyData=[];
dlData=[];
datas=json.commLineData;
for(var i=0;i<datas.length;i++){
var vol=datas[i].vol;
var cur=datas[i].cur;
var dateTime=datas[i].date;
var volArr=[dateTime,vol];
var curArr=[dateTime,cur];
dyData.push(volArr);
dlData.push(curArr);
} if(datas.length==0){ lineOption.xAxis[0].show=false;
}
lineOption.xAxis[0].min=startDate;
lineOption.xAxis[0].max=endDate;
//lineOption.xAxis[0].data=xData;
lineOption.yAxis[0].min=minVol;
lineOption.yAxis[0].max=maxVol;
lineOption.yAxis[1].min=minCur;
lineOption.yAxis[1].max=maxCur;
lineOption.series[0].data=dyData;
lineOption.series[1].data=dlData;
//lineChart.setOption(lineOption);
lineChart.setOption(lineOption);
} function reset(){
lineOption.series[0].data=[];
lineOption.series[1].data=[];
lineChart.setOption(lineOption);
} function setBorder(width,height){
$("#clc").css("width",width+"px").css("height",height+"px");
$(lineChart).resize();
} /*****js调用qt对象,调试时可以加入try...catch...捕获错误***/
$(function(){
var jsonObj=window.mywebkit.refreshRTData();
optionData(obj);
setInterval(function(){
jsonObj=window.mywebkit.refreshRTData();
optionData(obj);
},timeSplit*1000);
}); /*$(function(){
try{
// alert("start");
setInterval(function(){
try{
var obj=window.mywebkit.getDataLine();
// alert(obj);
optionData(obj);
}
catch(e)
{
alert("Error_2!");
}
},5000);
// alert("ok");
}
catch(e) {
alert("Error_1!");
}
});*/

最后分别列出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

关于qt QWebKit/QWebview 使用心得的更多相关文章

  1. QT的QWebView显示网页不全

    最近使用QWebView控件遇到一个问题,就是无论窗口多大,网页都显示那么大,而且,显示不完全,有滚动条 试过使用showMaximized()方法, 还是一样,网上一直说是布局问题,也没说清楚是虾米 ...

  2. Qt 【“QWebView/private/qwebview interface p.h”: No such file or directory】

    这种情况下需要在pro工程文件中添加 QT += webkitwidgets 然后清理当前工程, 重新构建,在运行即可. 如果还不行,那么在#include <QWebView>这样替换成 ...

  3. 关于QT安装的一些心得(QT551, VS2013)项目开发配置,以及项目结构分析

    推荐QT开发的配置如下: 我的硬件配饰中等,所以推荐一下配置: QT551版本,目前QT最新版8.0,为了稳定选择551版本 VS2013IDE, 因为VS2010与VS2013的编译器相同,但是VS ...

  4. 利用QT、QWebview、ffmpeg实现的屏幕录制方案

    .katex { display: block; text-align: center; white-space: nowrap; } .katex-display > .katex > ...

  5. Qt编程学习网站

    http://blog.csdn.net/k122769836/article/details/8637677 QT - little_su - 博客频道 - CSDN.NET Qt - 1+1=2 ...

  6. Qt4项目迁移到Qt5问题:greaterThan(QT_MAJOR_VERSION, 4): QT += widgets .

    文章来源:http://blog.csdn.net/ccf19881030/article/details/18220447 问题一:错误:C1083: 无法打开包括文件:"QApplica ...

  7. Java-Swing嵌入浏览器(二)

    这是qtjambi利用webview来做嵌入式浏览器,下面是我的工程目录. 运行效果如下图: 代码相关: package qtBowers; import com.trolltech.qt.core. ...

  8. Windows7下移植Qt4.8.4项目到QT5.2上时遇到的一些问题(包括三篇参考文章)

    文章来源:http://blog.csdn.net/ccf19881030/article/details/18220447 问题一:错误:C1083: 无法打开包括文件:“QApplication” ...

  9. Java_WebKit

    1. http://tieba.baidu.com/p/2807579276 下载地址: http://qtjambi.org/downloads https://qt.gitorious.org/q ...

随机推荐

  1. [转]:Android 5.0的调度作业JobScheduler

    参考:http://blog.csdn.net/cuiran/article/details/42805057 增加 JobScheduler 的同时,去掉了几个广播, CONNECTIVITY_AC ...

  2. UIView的alpha、hidden和opaque属性之间的关系和区别

    转自:http://blog.csdn.net/wzzvictory/article/details/10076323 作者:wangzz 原文地址:http://blog.csdn.net/wzzv ...

  3. 如何使用ILSpy 把发布版本反编译成源码

    有时候,看法别人写的代码比较好,想看看他们的代码到底是如何写的,于是就找方法,看看能否把发布版本变成源码.后来终于发现一个词“反编译”,我终于知道怎么办了. 工具:ILSpy   百度下载一个,该工具 ...

  4. [AWS vs Azure] 云计算里AWS和Azure的探究(2)

    Amazon EC2是Elastic Compute Cloud的简称,翻译成中文就是弹性计算云.它是Amazon云里面最基础的内容,也是发展到今天最成熟的部分,通过EC2, 你可以在Amazon的云 ...

  5. JAVA Zero Copy的相关知识【转】

    转自:https://my.oschina.net/cloudcoder/blog/299944 摘要: java 的zero copy多在网络应用程序中使用.Java的libaries在linux和 ...

  6. 设置Chrome忽略网站证书错误

    本人在XP下使用Chrome.总是莫名其妙的提示整数错误,一部分https网站无法直接访问.网上找了下,把解决思路记录下来. 解决这个问题很简单,只需要修改你平时用来启动Chrome的快捷方式就可以忽 ...

  7. Logstash写入MongoDB数据库

    1. 列出logstash-plugins bin/logstash-plugin list****** logstash-output-kafkalogstash-output-nagioslogs ...

  8. Python3判断shell下进程是否存在&&启动&&邮件通知

    判断进程是否存在 def isRunning(process_name): try: process = len(os.popen('ps aux | grep "' + process_n ...

  9. kkpager的改进,Ajax数据变化但是页码不变的有关问题

    kkpager的改进,Ajax数据变化但是页码不变的问题kkpager 是一个简单分页展示插件,需要依赖jquery.下载地址:http://www.oschina.net/action/projec ...

  10. 开源搜素引擎——Nutch

    Nutch简介 Nutch 是一个开源Java实现的搜索引擎.它提供了我们运行自己的搜索引擎所需的全部工具.包括全文搜索和Web爬虫. Nutch 是一个开源Java 实现的搜索引擎.它提供了我们运行 ...