Echarts是百度的可視化圖表庫(js),有各類漂亮的折線、餅、柱、雷達、散點圖,以前作網頁信息圖表時就體會到它具備很強大的表達能力(不單單是展現數據,更重要的是表達信息),因此很想把它集成到QT中,代替目前手頭已開發的軟件中的qwt。
目標:
在QT實現的軟件中嵌入Echarts折線圖,折線圖中的數據、標題等從qt部分傳給Echarts的js部分。javascript
實現:
1.在QT界面中使用QWebView來裝載一個包含Echarts折線圖的html頁面。
2.QT向html傳遞數據時使用json格式字符串。
3.html和js文件做爲QT RESOURCES打包編譯,這樣發佈時只有一個可執行程序,沒有額外的配置。html
遺留問題:多是操做系統的X11庫有bug,我遭遇了下面這樣的錯誤,有時在關閉界面時會coredump。java
XIO: fatal IO error 11 (資源暫時不可用) on X server "愼U" after 36191 requests (36190 known processed) with 0 events remaining.
使用到的開源軟件以下,很是感謝前人的輪子!!!
Echarts實例
qt與echarts配合打造最強圖表庫 個人代碼是在他的開源上的一些增長
cJSON 一個很是好用的C語言解析JSON的開源庫jquery
個人代碼文件結構以下所示,res目錄下是html和js文件,經過qrc文件指定資源,就能夠將其靜態打包到可執行程序中,cJSON是處理json結構對象和字符串的c庫,widget是處理加載頁面,傳參到js的qt程序
部分源碼在這裏,寫了一些註釋。
main.cppweb
#include "widget.h" #include <QApplication> #include <QTextCodec> int main(int argc, char *argv[]) { QTextCodec::setCodecForTr( QTextCodec::codecForName("utf8") ); QTextCodec::setCodecForCStrings( QTextCodec::codecForName("utf8") ); QTextCodec::setCodecForLocale( QTextCodec::codecForName("utf8") ); Q_INIT_RESOURCE(main); QApplication a(argc, argv); Widget w; w.show(); return a.exec(); }
widget.cppjson
#include <sys/time.h> #include "widget.h" #include "ui_widget.h" #include "cJSON.h" Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); ui->webView->load(QUrl("qrc:/res/curve.html")); //加載頁面 } Widget::~Widget() { delete ui; } void Widget::on_btnLine_clicked() { // 建立一些隨機數 float array[1440]; int max=1000, min=0; struct timeval tv_rand; for (int i=0; i<1440; i++) { gettimeofday(&tv_rand, (struct timezone*)0); srand(tv_rand.tv_usec); array[i] = (rand() % ((int)max*10000 - (int)min*10000))/10000.0 + min; } // 構建用於傳輸數據的json對象 cJSON *root; char *out; root=cJSON_CreateObject(); // json對象結構 {"title":"xxxxx", "value":[float array]} cJSON_AddStringToObject(root, "title", "日負荷曲線"); // 有中文的需求要注意使用UTF-8編碼 cJSON_AddItemToObject(root, "value", cJSON_CreateFloatArray(array, 1440)); out=cJSON_Print(root); // json對象轉字符串 cJSON_Minify(out); // 去掉字符串中的換行和縮進 QString str = QString(out); cJSON_Delete(root); // 把json字符串中全部雙引號前面再加上一個轉義符 // 由於這個字符串到了js裏面還要被parseJSON一次,因此\\不可少 str.replace(QRegExp("\""), "\\\""); // callfromqt是js中的函數名 str是其入參 QString strVal = QString("callfromqt(\"%1\");").arg(str); printf("strVal : %s \n", strVal.toStdString().c_str()); // 調用js中的函數 ui->webView->page()->mainFrame()->evaluateJavaScript(strVal); }
curve.htmlecharts
<!DOCTYPE html> <head> <meta charset="utf-8"> <title>ECharts</title> </head> <body> <!-- 爲ECharts準備一個具有大小(寬高)的Dom --> <div id="main" style="height:400px"></div> <!-- 由於連js都會被打包到可執行程序中,因此這裏引入echarts-all.js而不是require動態加載 --> <script src="jquery.min.js"></script> <script src="build/dist/echarts-all.js"></script> <script type="text/javascript"> // 基於準備好的dom,初始化echarts圖表, macarons是echarts主題,換樣式的,可略 var myChart = echarts.init(document.getElementById('main'),'macarons'); // 組織option var option = { title : { text: '' //名字由qt傳進來 }, tooltip:{ show : true, trigger: 'axis', // 座標軸觸發 也能夠item數據點觸發 formatter:function (params){ // tip的樣式 var res = '時間 : ' + params[0].name +'<br/>'; for (var i = 0, l = params.length; i < l; i++) { res += '<br/>' + params[i].seriesName + ' : ' + params[i].value; } return res; } }, calculable : false, xAxis : [ { type : 'category', boundaryGap : false, axisLabel:{interval:0}, data : [] } ], yAxis : [ { type : 'value' } ], series : [ { name:'今日', type:'line', data:[] } ] }; //窗體自適應 window.onresize = myChart.resize; // 爲echarts對象加載數據 function callfromqt(str) { var obj = $.parseJSON(str); // 可能個人QT版本有點低,webkit不能支持原生的JSON.parse if (obj.value.length < 1) return; option.title.text=obj.title; option.series[0].data = obj.value; // 下面是根據傳入的採樣點數拼座標軸 可略 option.xAxis[0].data = getDayXAsis(obj.value.length); if ( option.xAxis[0].data.length > 12) option.xAxis[0].axisLabel.interval = option.xAxis[0].data.length/12 -1; else option.xAxis[0].axisLabel.interval = 0; // 畫折線圖 myChart.setOption(option); } // 根據數據點數建立日曲線的x軸標籤 function getDayXAsis(split_num) { var xasis = []; // 若是是288點就5分鐘一個標籤 96點就15分鐘一個標籤 var offset = 86400/split_num; var d = new Date(1999, 1, 1); for (var i=0; i<split_num; i++) { var nd = new Date(); nd.setTime(d.getTime() +offset*1000*i); var str = compZero(nd.getHours(),2)+":"+compZero(nd.getMinutes(),2); xasis.push(str); } return xasis; } // 左補0 function compZero(intn, bits) { var int_str = "" + intn; if (int_str.length >= bits) return int_str; var comp_str = ""; var comp_len = bits - int_str.length; for (var i=0; i<comp_len; i++) comp_str += "0"; comp_str += int_str; return comp_str; } </script> </body>
小結:
QT向js傳遞參數中有中文的話,qt文件要存爲UTF-8的格式,不然會形成亂碼。
以json字符串傳遞參數是,要對引號再加一次轉義符,不然在js中沒法解析。
Echarts在網頁上展現數據的性能號稱20W數據秒級出圖,但在QT中出圖的動畫效果有明顯卡頓,但仍在可接受範圍內。dom