qt加載EChart並動態交互數據及動態設置大小的方法

QT有圖表庫,用來展示數據,比如QWT,QCustomPlot,QChart。QCustomPlot是一相對好用的輕量級的控件,QChart雖然說是QT框架內的,可是聽說性能極差,完全比不上QCustomPlot,而QWT是一個性能比較好的,且樣式也相比其它兩個來說,是相對豐富,重量級的庫,可是需要自己編譯配置環境,如果感興趣可以查看我其它的博客怎麼來編譯它。這裏我都不講以上三個庫,下面我相講的是QT怎麼來結合EChart做開發。

而EChart是一個很好的js圖表庫,圖表豐富,又好看,畢竟它不是QT體系內的,性能不知道怎樣,但是如果數據不多,我們完全可以用它來展示,可是在QT中怎麼調用它呢?

我們知道QT4有一個QWebView可以用來操作網頁,在QT5中則使用QWebEngineView。下面我來講一下具體操作。

一、QT加載ECharts

1,下載ECharts.js庫

官網下載http://echarts.baidu.com/download.html

2. 編寫.html加載echart.

可以從官網的example裏下載代碼示例

https://echarts.baidu.com/examples/

然後點擊一個示例,就可以打開示例頁面,然後在示例頁面右下角點擊“Download"按鈕,即可將示例代碼下載下來。

3.新建一個工程

4.在QT工程下新建一文件夾,並將echarts.js或,echarts.min.js和前面下載的示例html文件,放入同一文件夾中。

5 更改示例html文件內容,如下,(其中一定要注意加載echarts.js的路徑)會前端開發的一下就能看明白,但對於每一個程序員來說,這些代碼也不難懂,非常簡單。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts</title>
    <!-- 引入 echarts.js -->
    <script src="./echarts.js"></script>
</head>
<body>
    <!-- 爲ECharts準備一個具備大小(寬高)的Dom -->
    <div id="main" style="width: 750px;height:450px;"></div>
    <script type="text/javascript">
        // 基於準備好的dom,初始化echarts實例
        var myChart = echarts.init(document.getElementById('main'));
		var option = {
			title: {
				text: "對數軸示例",
				x: "center"
			},
			tooltip: {
				trigger: "item",
				formatter: "{a} <br/>{b} : {c}"
			},
			legend: {
				x: 'left',
				data: ["2的指數", "3的指數"]
			},
			xAxis: [
				{
					type: "category",
					name: "x",
					splitLine: {show: false},
					data: ["一", "二", "三", "四", "五", "六", "七", "八", "九"]
				}
			],
			yAxis: [
				{
					type: "log",
					name: "y"
				}
			],
			toolbox: {
				show: true,
				feature: {
				mark: {
					show: true
				},
				dataView: {
					show: true,
					readOnly: true
				},
				restore: {
					show: true
				},
				saveAsImage: {
					show: true
				}
			}
			},
			calculable: true,
			series: [
				{
					name: "3的指數",
					 type: "line",
					data: [1, 3, 9, 27, 81, 247, 741, 1223, 5669]

				},
				{
					name: "2的指數",
					type: "line",
					data: [1, 2, 4, 8, 16, 32, 64, 228, 156]

				}
			]
			};

			myChart.setOption(option);
			
    </script>
</body>
</html>

5. 左qt工程中,雙擊打開界面ui,在UI編輯器中添加一個widget,並將widget提升爲“QWebEngineView”(這裏是以QT5.9.3爲例)

6.然後再mainwindow.cpp中添加如下代碼,以運行QWebEngineView來加載剛剛改好的.html頁面。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    ui->widget->setContextMenuPolicy(Qt::NoContextMenu);
    ui->widget->load(QUrl("E:/workspace/QT_PRJ/echartsTest/htmlEcharts/testEcharts.html"));

   

}

好了,到這裏就可以顯示出一個加載了echarts的html頁面了。

二、QT與ECharts交互

上面我們已經知道,QT是通過QWebEngineView來調用HTML頁面的,而在HTML中通過JS來調用ECharts。

1.封裝設置ECharts屬性的JS方法

QT可以通過QWebEngineView調用加載的html頁面中的JS方法,所以我們要將.HTML頁面中JS設置ECharts屬性的那段代碼封裝成一個方法

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts</title>
    <!-- 引入 echarts.js -->
    <script src="./echarts.js"></script>
</head>
<body>
    <!-- 爲ECharts準備一個具備大小(寬高)的Dom -->
    <div id="main" style="width: 750px;height:450px;"></div>
    <script type="text/javascript">
        // 基於準備好的dom,初始化echarts實例
        var myChart = echarts.init(document.getElementById('main'));
		function init(){
		var option = {
			title: {
				text: "對數軸示例",
				x: "center"
			},
			tooltip: {
				trigger: "item",
				formatter: "{a} <br/>{b} : {c}"
			},
			legend: {
				x: 'left',
				data: ["2的指數", "3的指數"]
			},
			xAxis: [
				{
					type: "category",
					name: "x",
					splitLine: {show: false},
					data: ["一", "二", "三", "四", "五", "六", "七", "八", "九"]
				}
			],
			yAxis: [
				{
					type: "log",
					name: "y"
				}
			],
			toolbox: {
				show: true,
				feature: {
				mark: {
					show: true
				},
				dataView: {
					show: true,
					readOnly: true
				},
				restore: {
					show: true
				},
				saveAsImage: {
					show: true
				}
			}
			},
			calculable: true,
			series: [
				{
					name: "3的指數",
					 type: "line",
					data: [0, 0, 0, 0, 0, 0, 0, 0, 0]

				},
				{
					name: "2的指數",
					type: "line",
					data: [0, 0, 0, 0, 0, 0, 0, 0, 0]

				}
			]
			};

			myChart.setOption(option);
		}
		
		
		init();
    </script>
</body>
</html>

可以看到,我將設置屬性封裝成了一個方法,然後再自調用了一次,可以保證在執行程序初始化的時候可以顯示出圖表,其中我將加載的數據都設置成了0,所以顯示的是一個空的圖表,看不到曲線。

2.封裝帶參數設置ECharts屬性的JS方法

QT與EChart交互得傳遞數據,那麼我們只封裝了一個不帶參數的方法是不能從外面設置數據的,我們可以封裝成了一個帶參數的方法,這個參數則是我們要顯示的數據,這個參數我們用JSON的格式來傳遞,它可以傳遞多條曲線的數據。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>ECharts</title>
    <!-- 引入 echarts.js -->
    <script src="./echarts.js"></script>
</head>
<body>
    <!-- 爲ECharts準備一個具備大小(寬高)的Dom -->
    <div id="main" style="width: 750px;height:450px;"></div>
    <script type="text/javascript">
        // 基於準備好的dom,初始化echarts實例
        var myChart = echarts.init(document.getElementById('main'));
		function init(){
		var option = {
			title: {
				text: "對數軸示例",
				x: "center"
			},
			tooltip: {
				trigger: "item",
				formatter: "{a} <br/>{b} : {c}"
			},
			legend: {
				x: 'left',
				data: ["2的指數", "3的指數"]
			},
			xAxis: [
				{
					type: "category",
					name: "x",
					splitLine: {show: false},
					data: ["一", "二", "三", "四", "五", "六", "七", "八", "九"]
				}
			],
			yAxis: [
				{
					type: "log",
					name: "y"
				}
			],
			toolbox: {
				show: true,
				feature: {
				mark: {
					show: true
				},
				dataView: {
					show: true,
					readOnly: true
				},
				restore: {
					show: true
				},
				saveAsImage: {
					show: true
				}
			}
			},
			calculable: true,
			series: [
				{
					name: "3的指數",
					 type: "line",
					data: [0, 0, 0, 0, 0, 0, 0, 0, 0]

				},
				{
					name: "2的指數",
					type: "line",
					data: [0, 0, 0, 0, 0, 0, 0, 0, 0]

				}
			]
			};

			myChart.setOption(option);
		}
		
		function init2(str){
		var option = {
			title: {
				text: "對數軸示例",
				x: "center"
			},
			tooltip: {
				trigger: "item",
				formatter: "{a} <br/>{b} : {c}"
			},
			legend: {
				x: 'left',
				data: ["2的指數", "3的指數"]
			},
			xAxis: [
				{
					type: "category",
					name: "x",
					splitLine: {show: false},
					data: ["一", "二", "三", "四", "五", "六", "七", "八", "九"]
				}
			],
			yAxis: [
				{
					type: "log",
					name: "y"
				}
			],
			toolbox: {
				show: true,
				feature: {
				mark: {
					show: true
				},
				dataView: {
					show: true,
					readOnly: true
				},
				restore: {
					show: true
				},
				saveAsImage: {
					show: true
				}
			}
			},
			calculable: true,
			series: [
				{
					name: "3的指數",
					 type: "line",
					data: str["data1"]

				},
				{
					name: "2的指數",
					type: "line",
					data: str["data2"]

				}
			]
			};

			myChart.setOption(option);
		}
		

        window.onresize = myChart.resize ;
		init();
    </script>
</body>
</html>

3.QT調用JS方法顯示數據

1)QWebEngineView可以調用它的page()->runJavaScript("function(str)")來運行JS方法。

2)在QT中我們需要組成一個JSON字符串將數據傳過去,所以我們需要用到QJonsObject來組成一個JSON對象,使用QJsonArray往JSON對象中添加一數組,使用QJsonDocument來將JSON對象轉化成字符串。

接下來在QT工程中的UI界面中增加一個QPushButton並添加信號和槽函數,在槽函數中添加如下代碼

void MainWindow::on_test2_clicked()
{
    QJsonObject seriesData;
    QJsonArray data1 = {1, 3, 9, 27, 81, 247, 741, 2223, 6669};
    seriesData.insert("data1", data1);
    QJsonArray data2 = {1, 2, 4, 8, 16, 32, 64, 128, 256};
    seriesData.insert("data2", data2);

    QString optionStr = QJsonDocument(seriesData).toJson();
    QString js = QString("init2(%1)").arg(optionStr);
    ui->widget->page()->runJavaScript(js);
}

然後運行程序,點擊剛添加的Button就可以加載出數據了。

三、控制ECharts的大小

我們可以從HTML代碼中可以看到,它定義了一個id爲main的元素,並設置了style屬性width,和height。

<div id="main" style="width: 750px;height:450px;"></div>

並在js裏用這個"main"初始化echarts實例,

// 基於準備好的dom,初始化echarts實例
var myChart = echarts.init(document.getElementById('main'));

所以EChart的大小爲750*450px,那麼你們肯定會想,我們將<div>標籤中的style的width和height設置爲自動不就可以了嗎?

<div id="main" style="width: 100%;height:100%;"></div>

或者

<div id="main" style="width: auto;height:auto;"></div>

開始我也是這麼想的,可是通過試驗這個行不通,QT在運行頁面時會報錯,並且也達不到預想的效果,只有設置爲一個固定的*px時才能改變大小,所以我又將設置main標籤的大小封裝成了一個JS方法。代碼如下。

function setSize(size){
			// 首先是取到元素
			var main = document.getElementById('main');
			main.style.width = size["width"] + "px";
			main.style.height = size["height"] + "px";
			myChart.resize();
		}

同樣也是通過JSON來傳遞數據,然後在QT中添加一個槽(SLOT)函數,代碼如下:

void MainWindow::onResizeEcharts()
{
    isLoaded = true;
    QJsonObject sizeData;
    sizeData.insert("width", ui->widget->width() - 20);
    sizeData.insert("height", ui->widget->height() - 20);
    QString sizeStr = QJsonDocument(sizeData).toJson();
    QString js = QString("setSize(%1)").arg(sizeStr);
    ui->widget->page()->runJavaScript(js);
}

可以看到,我是依據QWebEngineView的大小來設置EChart的大小的,其中的isLoaded是判斷頁面是否完成 加載的標誌,因爲我們實現在窗口改變大小時ECharts也跟着變化,所以我們要在resizeEvent時設置也要設置大小,可是程序一運行它會執行一次,會導致還沒加載完html頁面它就執行了,然後報錯,所以我加了一個標誌來判斷,因爲QWebEngineView在load完一個頁面後會發出一個已完成的信號,只有在load完成後我將這個標誌設置爲true就不會報錯了。具體代碼如下。

在.h文件中添加resizeEvent方法和isLoaded標誌

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtWebEngineWidgets/QWebEngineView>
#include <QResizeEvent>

namespace Ui
{
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:

    void on_test_clicked();

    void on_test2_clicked();

    void onResizeEcharts();

protected:
    virtual void resizeEvent(QResizeEvent *event) override;

private:
    Ui::MainWindow *ui;
    bool isLoaded;
};

#endif // MAINWINDOW_H

在.cpp中添加

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    isLoaded = false;
    ui->widget->setContextMenuPolicy(Qt::NoContextMenu);
    ui->widget->load(QUrl("E:/workspace/QT_PRJ/echartsTest/htmlEcharts/testEcharts.html"));

    connect(ui->widget, SIGNAL(loadFinished(bool)), this, SLOT(onResizeEcharts()));

}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    if(isLoaded)
        onResizeEcharts();
}

然後運行程序就可以動態的改變ECharts的大小了。

時間有點趕,寫得有點粗糙。。。共同學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章