我一個研究嵌入式的,不知道怎麼就迷上了上位機,接了幾個項目都是關於Qt,這個項目仍是比較經典的,本身沒事兒的時候也進行研究,對這個軟件進行升級,反正,我喜歡編程,喜歡研究這些東西。研究了一下午,查了不少資料,看了不少的例子,我對於JS是0基礎,能稍微看懂一點點HTML語言的東西,下午調試了好幾遍,運行了好幾遍,終於在我更改了JavaScript的函數完畢以後,一會兒數據回傳成功了,那種感受很棒!!!特意寫這個博客,記錄個人研發成果。javascript
【正文】css
QWebChannel官方給的例子是和Socket混合,看的是一頭霧水,不得不吐槽Qt了,能不能單獨講講使用方法,別和別的東西結合?!html
對於個人GPS地圖項目,研究又有了新的進展,我在本年度一直在業餘時間研究Qt開發的軟件和網頁交互(JS和HTML),雖然我對於網頁的知識僅僅有個基礎,在業餘方面,我也不斷的在對該軟件進行升級研究,目前狀態:java
到目前爲止,GPS定位系統交互驅動百度地圖已經徹底適配QWebEngine組件。c++
如圖1:web
紅色方框部分爲當前鼠標的經緯度信息,這個信息來源於html訪問百度地圖的JavaScript,而後回傳給C++的信息。編程
本文重點來講一下,如何從JavaScript獲取回傳信息,實現交互api
我是非專業的,我也沒有找關於HTML和JS交互的書,在我研究的過程當中我認爲是一個這樣的關係:函數
QWebEngine提供了調用HTML裏面JavaScript的方法,這裏HTML像是一個接口,在HTML尾部有一個這樣的標籤, ,在這個標籤內的函數和變量體中寫入一些函數和變量,這些函數和變量要麼是JavaScript中的調用,要麼是Qt中的調用,因此,HTML像是一個QT和網頁的橋樑。在下面的章節,咱們詳細討論一下步驟。ui
要使用QWebChannel要打點好兩個方面,第一,Qt方面,須要包含QWebChannel類,註冊好QWebChannel須要鏈接的Qt的對象;第二,JS方面,官方提供了配套的qwebchannel.js文件,這個js文件就至關於駐JavaScript負責通訊的。所需準備的:
下面就這兩方面討論如何使用:
地圖這塊僅有一個JavaScript文件,是驅動百度地圖的,可是爲了讓QWebChannel和百度的JS順利通訊,Qt提供了一個qwebchannel.js文件,這個文件就是負責打點Qt和JS通訊用的。
參考源碼:我把qwebchannel.js放在和百度地圖提供的js(也就是你要通訊的JS)放在了一個目錄,而後在HTML文件中要引入兩個js文件。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>地圖演示</title> <script src="js/qwebchannel.js"></script> <!--> !!!!!!重點1<--> <script src="js/apiv1.3.min.js"></script> <!--script type="text/javascript" src="http://api.map.baidu.com/api?v=1.3"></script--> <link rel="stylesheet" type="text/css" href="bmap.css"/> </head> <body> <div style="left:0;top:0;width:100%;height:100%;position:absolute;" id="container"></div> </body> </html> <script> var mapOptions={ minZoom: 3, maxZoom:19, mapType: BMAP_NORMAL_MAP } var map = new BMap.Map("container",mapOptions); // 設置街道圖爲底圖 var point = new BMap.Point(116.468278, 39.922965); // 建立點座標 map.centerAndZoom(point,14); // 初始化地圖,設置中心點座標和地圖級別。 map.addControl(new BMap.NavigationControl({offset: new BMap.Size(10, 90)})); map.enableScrollWheelZoom(); // 啓用滾輪放大縮小。 map.enableKeyboard(); // 啓用鍵盤操做。 map.enableContinuousZoom(); // 啓用連續縮放 var myIcon = new BMap.Icon("images/Point.png", new BMap.Size(20,25)); var marker = new BMap.Marker(point,{icon:myIcon}); // 建立標註 map.addOverlay(marker); // 加載標註 // !!!!重點2!!! new QWebChannel(qt.webChannelTransport, function(channel){ window.bridge = channel.objects.person; // 註冊 } ); var dragFlag=false; // !!!!重點3!!! var updateInfo = function(lng,lat) { window.bridge.getCoordinates(lng,lat); } function showAddress(longjitude,latitude) { var gpsPoint = new BMap.Point(longjitude, latitude); if(!dragFlag) { map.panTo(gpsPoint); } marker.setPosition(gpsPoint); } function showStreetMap() { map.setMapType(BMAP_NORMAL_MAP); }; function showSatelliteMap() { map.setMapType(BMAP_SATELLITE_MAP); } // !!!!!重點4!!! map.addEventListener("mousemove",function(e) { updateInfo(e.point.lng,e.point.lat); }); map.addEventListener("dragstart",function(e){ dragFlag=true; }); map.addEventListener("dragend",function(e){ dragFlag=false; }); map.addEventListener("zoomend",function(e){ }); </script>
這麼多代碼,看的你很焦躁,不用太細研究,裏面只是定義了不少百度地圖讀取的方法,咱們把重點放在幾個點上(你能夠在上面的源碼註釋中找到重點標記)
<script src="js/qwebchannel.js"></script> <script src="js/apiv1.3.min.js"></script>
,這兩個語句表示這個HTML負責驅動兩個js文件,一個是百度地圖的js文件,一個是qwebchannel的js文件,qwebchannel毋庸置疑就是負責交互數據的了,因此在你拿到百度地圖原版的HTML文件的時候,須要對這裏進行改進,原理貌似就像是C語言中#include這塊,把qwebchannel.js集成進來。// !!!!重點2!!! new QWebChannel(qt.webChannelTransport, // 新建一個QWebChannel實例化 function(channel){ window.bridge = channel.objects.person; // 註冊 // window.bridge不用找了,這個是js的功能函數,等號後邊須要注意,channel.objects.XXXXX } // 這個XXXX是須要在Qt C++程序裏面定義的,咱們一下子說,可是channel.objects.這個是固有的。 );
這部分是新添加的,我查了QWebChannel這個東西在qwebchannel.js文件中定義了,這裏在咱們要訪問的HTML中必需要有這個東西的定義,解釋詳見註釋。person這個東西就是在C++裏面定義的,就當是他是負責和咱們C++和js通訊的句柄吧。將他賦值給window.bridge,之後利用操做window.bridge咱們就能夠通訊了。
// !!!!重點3!!! var updateInfo = function(lng,lat) { window.bridge.getCoordinates(lng,lat); }
這裏定義一個函數,就是將lng和lat這兩個參數傳遞給Qt C++,經過這樣的方式就能回傳數據了。window.bridge說過了是固有的,js固有的,那麼getCoordinates這個東西是什麼?答曰,是咱們Qt C++裏面自定義的一個槽函數,聲明在public slots:裏面,channel經過window.bridget來操控槽函數,達到數據回傳,這個地方是重中之重!!
// !!!!!重點4!!! map.addEventListener("mousemove",function(e) { updateInfo(e.point.lng,e.point.lat); });
當發生mousemove這個行爲的時候,這多是JS裏面的知識,則調用function(e),必定要注意這個function不能直接把函數體寫在這裏,必須採用咱們上面的方法,把函數體單獨寫,而後在內部寫上調用。
到此javascript部分已經交代清楚了。
Qt C++方面的開發,須要啓動QWebChannel類,註冊頁面。
// 準備Javascript文件交互 QString strMapPath = "qrc:/map/map.html"; // 設定地圖路徑 QWebEnginePage *page = new QWebEnginePage(this); // 定義QWebEnginePage界面負責打開html文件 QWebChannel *channel = new QWebChannel(this); // 定義QWebChannel負責 channel->registerObject(QString("person"),this); // QWebChannel對Widget類,註冊一個person的通訊介質 / // 在js文件中person負責成爲window.bridge / // 在this中也就是Widget類註冊channel,channel訪問的位Widget下的槽函數。 page->load(strMapPath); // webenginePage加載html地圖。 page->setWebChannel(channel); // webenginePage加載Channel功能 ui->webEngine->setPage(page); // ui顯示該page。
在C++類Widget的構造函數,要進行準備,這裏涉及了QWebEnginePage,QWebChannel,千萬別亂,按照代碼註釋裏清楚關係。這裏有個QString類,定義了person,在返回去看js中的person,是否是明白了其中的聯繫了?!你能夠寫成任意可理解的字符。
緊接着就是槽函數了:必須是public slots: 不能是private slots
public slots: void getCoordinates(QString lon, QString lat) { QString tempLon="Mouse Lontitude:"+lon+"°"; QString tempLat="Mouse Lattitude:"+lat+"°"; ui->label_mouse_altitude->setText(tempLat); ui->label_mouse_latitude->setText(tempLon); };
通過以上,js會回傳數據給lon和lat,而後你該怎麼辦就怎麼辦了。
通過一下午的努力,完成了數據回傳,能夠將js的數據傳遞回來,可是QWebChannel這塊還有其餘的東西,好比和槽和信號鏈接,若是從此能遇到這個項目,我會繼續研究,不然,到今天這個項目完畢。
感謝觀看。
【木有】
1. 本文爲MULTIBEANS團隊研發跟隨文章,未經容許不得轉載。
2· 文中涉及的內容如有侵權行爲,請與本人聯繫,本人會及時刪除。
3· 尊重成果,本文將用的參考文獻所有給出,向無私的工程師,愛好者致敬。