Qt的QWebChannel和JS、HTML通訊/交互驅動百度地圖

Qt的QWebChannel和JS、HTML通訊/交互驅動百度地圖

0 前言

我一個研究嵌入式的,不知道怎麼就迷上了上位機,接了幾個項目都是關於Qt,這個項目仍是比較經典的,本身沒事兒的時候也進行研究,對這個軟件進行升級,反正,我喜歡編程,喜歡研究這些東西。研究了一下午,查了不少資料,看了不少的例子,我對於JS是0基礎,能稍微看懂一點點HTML語言的東西,下午調試了好幾遍,運行了好幾遍,終於在我更改了JavaScript的函數完畢以後,一會兒數據回傳成功了,那種感受很棒!!!特意寫這個博客,記錄個人研發成果。javascript

  • 我是一個業餘研究Qt的,不是那麼專業! *

【正文】css

QWebChannel官方給的例子是和Socket混合,看的是一頭霧水,不得不吐槽Qt了,能不能單獨講講使用方法,別和別的東西結合?!html

對於個人GPS地圖項目,研究又有了新的進展,我在本年度一直在業餘時間研究Qt開發的軟件和網頁交互(JS和HTML),雖然我對於網頁的知識僅僅有個基礎,在業餘方面,我也不斷的在對該軟件進行升級研究,目前狀態:java

  • 第一階段:在Qt5.6如下版本,Qt尚未刪除QWebKits組件,基於QWebKits組件,我作了最基本的軟件:參考:Qt開發北斗定位系統融合百度地圖API及Qt程序打包發佈
  • 第二階段:Qt5.6以上版本,刪除了QWebKits組件,升級爲QWebEngine組件,可是過渡階段只能由Qt的C++程序去運行JS,JS反饋的數據沒法回傳,這形成了我獲取當前鼠標經緯度的功能缺失。參考:QtWebkits如何向QtWebEngine過渡
  • 第三階段:基於第二個階段,依舊基於QWebEngine,引入QWebChannel通訊機制,完成JavaScript給的回傳數據,還原了鼠標當前經緯度的獲取功能。

到目前爲止,GPS定位系統交互驅動百度地圖已經徹底適配QWebEngine組件。c++

如圖1:經緯度功能展現web

紅色方框部分爲當前鼠標的經緯度信息,這個信息來源於html訪問百度地圖的JavaScript,而後回傳給C++的信息。編程

本文重點來講一下,如何從JavaScript獲取回傳信息,實現交互api

1 實現過程

1.1 原理闡述

我是非專業的,我也沒有找關於HTML和JS交互的書,在我研究的過程當中我認爲是一個這樣的關係:函數

原理闡述

QWebEngine提供了調用HTML裏面JavaScript的方法,這裏HTML像是一個接口,在HTML尾部有一個這樣的標籤, ,在這個標籤內的函數和變量體中寫入一些函數和變量,這些函數和變量要麼是JavaScript中的調用,要麼是Qt中的調用,因此,HTML像是一個QT和網頁的橋樑。在下面的章節,咱們詳細討論一下步驟。ui

1.2 WebChannel的使用

要使用QWebChannel要打點好兩個方面,第一,Qt方面,須要包含QWebChannel類,註冊好QWebChannel須要鏈接的Qt的對象;第二,JS方面,官方提供了配套的qwebchannel.js文件,這個js文件就至關於駐JavaScript負責通訊的。所需準備的:

  • 【JS方面:】qwebchannel.js文件(Qt官方提供,須要在html中引入,拿到后里面什麼代碼都不要修改,直接使用。qwebchannel.js下載地址
  • 【Qt方面:】在Qt的主程序中,建立好QWebChannel類

下面就這兩方面討論如何使用:

1.2.1 JS方面處理

地圖這塊僅有一個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>

這麼多代碼,看的你很焦躁,不用太細研究,裏面只是定義了不少百度地圖讀取的方法,咱們把重點放在幾個點上(你能夠在上面的源碼註釋中找到重點標記)

  • 【第1步】:<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步】:須要在JS這塊建立一個QWebChannel,這個js裏的webchannel就是負責和Qt C++裏面的webchannel通訊的。
// !!!!重點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步】:利用channel這個東西通訊。
// !!!!重點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步】:配合監聽器,這裏有個注意點。
// !!!!!重點4!!!
map.addEventListener("mousemove",function(e) {      

    updateInfo(e.point.lng,e.point.lat);

});

當發生mousemove這個行爲的時候,這多是JS裏面的知識,則調用function(e),必定要注意這個function不能直接把函數體寫在這裏,必須採用咱們上面的方法,把函數體單獨寫,而後在內部寫上調用。

到此javascript部分已經交代清楚了。

1.2.2 Qt C++方面處理

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,而後你該怎麼辦就怎麼辦了。

2 總結

通過一下午的努力,完成了數據回傳,能夠將js的數據傳遞回來,可是QWebChannel這塊還有其餘的東西,好比和槽和信號鏈接,若是從此能遇到這個項目,我會繼續研究,不然,到今天這個項目完畢。

感謝觀看。

參考文獻:

【木有】


版權聲明:

1. 本文爲MULTIBEANS團隊研發跟隨文章,未經容許不得轉載。

2· 文中涉及的內容如有侵權行爲,請與本人聯繫,本人會及時刪除。

3· 尊重成果,本文將用的參考文獻所有給出,向無私的工程師,愛好者致敬。

相關文章
相關標籤/搜索