日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

[Qt] 利用QtWebKit完成JavaScript访问C++对象

發(fā)布時(shí)間:2023/12/10 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [Qt] 利用QtWebKit完成JavaScript访问C++对象 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

http://blog.csdn.net/longsir_area/article/details/42965565

一. 介紹?? ??? ??

?在瀏覽器擴(kuò)展或者WebApp的項(xiàng)目經(jīng)常用的腳本語言JavaScript有很多局限性,比如,javascript語言不能夠夸窗口訪問js對(duì)象,不能直接讀寫磁盤文件(這個(gè)也正是發(fā)明人設(shè)計(jì)的安全機(jī)制吧,要不然,誰還敢用瀏覽器啊,幾行代碼就可以把你偷窺的一覽無余),我們可能在我們的程序中需要擴(kuò)展這個(gè)功能。


那么,我們?cè)趺唇鉀Q這些問題呢?或許你可以參考一下下面的設(shè)計(jì)架構(gòu)。


UI利用Html + CSS + JavaScript編寫,核心業(yè)務(wù)層利用C++編寫,C++和JavaScript對(duì)象主要通過WebKit通信。讓相應(yīng)的語言做它們擅長的事情,這就是這種架構(gòu)的核心。


WebKit又是什么呢?簡單言之就是一種瀏覽器內(nèi)核引擎,Safari、Chrome、FireFox等瀏覽器都采用WebKit引擎作為內(nèi)核,由此可見WebKit的地位了,我們正是利用WebKit來做javascript的擴(kuò)展的,Qt界又對(duì)WebKit做了一層封裝,這樣,開發(fā)者對(duì)WebKit就更加容易上手了。


更幸運(yùn)的是,QtWebKit提供了一種將QObject對(duì)象擴(kuò)展到Javascript運(yùn)行環(huán)境的機(jī)制,這樣,JavaScript代碼將有權(quán)限訪問QObject對(duì)象,?QObject對(duì)象的所有屬性也能在Javascript上下文中被訪問。


那么,如何利用QtWebKit使得js和c++相互通信呢?


二. 搭建框架

首先,我們需要一個(gè)js代碼能夠運(yùn)行的環(huán)境

我們準(zhǔn)備一個(gè)主窗口,在主窗口內(nèi)部添加WebView控件,使得程序具有執(zhí)行js的能力;

MainWindow的定義

[cpp]?view plaincopy
  • #include?<QMainWindow>??
  • #include?<QGraphicsView>??
  • #include?<QGraphicsWebView>??
  • #include?<QGraphicsScene>??
  • #include?<QEvent>??
  • ??
  • #include?"External.h"??
  • ??
  • class?MainWindow?:?public?QGraphicsView??
  • {??
  • ????Q_OBJECT??
  • public:??
  • ????MainWindow(QWidget?*parent?=?0);??
  • ????virtual?~MainWindow();??
  • ??
  • private:??
  • ????QGraphicsWebView*???m_pWebView;??
  • ????QGraphicsScene*?????m_pScene;??
  • };??
  • ??
  • #endif?//?MAINWINDOW_H??

  • MainWindow的實(shí)現(xiàn)

    [cpp]?view plaincopy
  • #include?"mainwindow.h"??
  • ??
  • #include?<QWebFrame>??
  • #include?<QLayout>??
  • ??
  • MainWindow::MainWindow(QWidget?*parent)??
  • ????:?QGraphicsView(parent)??
  • {??
  • ????this->resize(?QSize(?800,?600)?);??
  • ??????
  • ????m_pScene?=?new?QGraphicsScene(this);??
  • ????if(NULL?!=?m_pScene)??
  • ????{??
  • ????????m_pWebView?=?new?QGraphicsWebView;??
  • ??
  • ????????if(?NULL?!=?m_pWebView)??
  • ????????{??
  • ????????????//enabled?javascript??
  • ????????????QWebSettings?*settings?=?m_pWebView->page()->settings();??
  • ??
  • ????????????settings->setAttribute(QWebSettings::JavascriptEnabled,true);????
  • ????????????settings->setAttribute(QWebSettings::JavascriptCanAccessClipboard,true);??
  • ????????????settings->setAttribute(QWebSettings::DeveloperExtrasEnabled,true);??
  • ????????????settings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls,?true);??
  • ????????????settings->setAttribute(QWebSettings::LocalContentCanAccessFileUrls,?true);??
  • ????????????settings->setAttribute(QWebSettings::JavascriptCanCloseWindows,?true);??
  • ????????????settings->setAttribute(QWebSettings::AutoLoadImages,true);??
  • ??
  • ????????????m_pScene->addItem(?m_pWebView?);??
  • ????????????this->setScene(?m_pScene?);??
  • ????????}??
  • ????}???
  • }??
  • ??
  • MainWindow::~MainWindow()??
  • {??
  • ??
  • }??

  • QWebSettings類是用于配置Web運(yùn)行環(huán)境,我們首先配置了JavaScriptEnable=true,使得這個(gè)web環(huán)境能夠運(yùn)行js代碼,其他的選項(xiàng)不是必要的。



    三. 添加QObject到j(luò)s上下文


    利用QWebFrame提供的方法我們可以很輕松的完成添加對(duì)象:

    void addToJavaScriptWindowObject(const QString &name, QObject *object, ValueOwnership ownership = QtOwnership);

    注解:

    addToJavaScriptWindowObject這個(gè)方法可以使c++對(duì)象object在js的上下中以name為名字而出現(xiàn),object對(duì)象將被當(dāng)作這個(gè)QWebFrame的一個(gè)子對(duì)象,這樣,我們就可以把這個(gè)對(duì)象當(dāng)作js的一個(gè)對(duì)象來使用了;

    object對(duì)象的屬性和槽都作為js方法在js上下文中展開,因此,js拿到這個(gè)對(duì)象就可以很隨意的訪問這個(gè)對(duì)象的屬性和方法;

    當(dāng)這個(gè)頁面析構(gòu)后,這個(gè)對(duì)象在js上下文中也將消失,監(jiān)聽到信號(hào)javaScriptWindowObjectCleared() 后來重新調(diào)用下addToJavaScriptWindowObject即可。


    我們先寫一個(gè)測(cè)試頁面index.html,主要功能就是測(cè)試Js是否能夠訪問external對(duì)象;

    [html]?view plaincopy
  • <!DOCTYPE?html?PUBLIC?"-//W3C//DTD?XHTML?1.0?Transitional//EN"?"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">??
  • <html?xmlns="http://www.w3.org/1999/xhtml">??
  • <head>??
  • <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>??
  • <title>QWebKitDemo</title>??
  • <script?type="text/javascript">??
  • ??
  • window.onload?=?function(){??
  • ??
  • ????var?btnTest?=?document.getElementById("testCObj");??
  • ????btnTest.onclick?=?function()?{??
  • ????????alert(external);??
  • ????}??
  • }??
  • </script>??
  • </head>??
  • <body>??
  • ????<input?type="button"?id="testCObj"?value="測(cè)試C++對(duì)象">??
  • </body>??
  • </html>??

  • 我們先來定義一個(gè)繼承自QObject的類External,其中,繼承自QObject很關(guān)鍵,否則我們無法完成我們的功能;

    External類的定義,這里我定義了一個(gè)帶屬性、信號(hào)、槽、帶Q_INVOKABLE修飾的方法,這將在其他小節(jié)會(huì)用到

    [cpp]?view plaincopy
  • #ifndef?EXTERNAL_H??
  • #define?EXTERNAL_H??
  • ??
  • #include?<QObject>??
  • ??
  • class?External?:?public?QObject??
  • {??
  • ????Q_OBJECT??
  • ????Q_PROPERTY(QString?msg?READ?getMsg?WRITE?setMsg)?//?聲明靜態(tài)屬性msg??
  • public:??
  • ????explicit?External(QObject?*parent?=?0);??
  • ??
  • signals:??
  • ????void?mouseClicked();??
  • public?slots:??
  • ????void?TestPassObject(QObject*);??
  • ??
  • public:??
  • ??
  • ????QString?getMsg()?const?{?return?msg;?}??
  • ????void?setMsg(?const?QString&?strMsg?)?{?msg?=?strMsg;?}??
  • ??
  • ????//?提供給Javascript方法,需要用Q_INVOKABLE修飾??
  • ????Q_INVOKABLE?int?VerifyUserAccount(const?QString&?userName,?const?QString&?userPwd);??
  • ??
  • ????Q_INVOKABLE?QString?GetPropMsg();??
  • ??
  • ????Q_INVOKABLE?void?TestPassObjectToNative(QObject*);??
  • ??
  • ????QString?msg;??
  • };??
  • ??
  • #endif?//?EXTERNAL_H??

  • 我們?yōu)镸ainWindow類添加成員External對(duì)象指針

    [cpp]?view plaincopy
  • External*?m_pExternal;??

  • 在MainWindow的構(gòu)造方法中對(duì)m_pExternal實(shí)例化,并為這個(gè)頁面的javaScriptWindowObjectCleared信號(hào)關(guān)了槽函數(shù)AddJavascriptWindowObject

    這樣,我們的MainWindow.h和MainWindow.cpp就成這樣子了:


    MainWindow.h

    [cpp]?view plaincopy
  • #include?<QMainWindow>??
  • #include?<QGraphicsView>??
  • #include?<QGraphicsWebView>??
  • #include?<QGraphicsScene>??
  • #include?<QEvent>??
  • ??
  • #include?"External.h"??
  • ??
  • class?MainWindow?:?public?QGraphicsView??
  • {??
  • ????Q_OBJECT??
  • public:??
  • ????MainWindow(QWidget?*parent?=?0);??
  • ????virtual?~MainWindow();??
  • public?slots:??
  • ????void?AddJavascriptWindowObject();??
  • ??
  • private:??
  • ????QGraphicsWebView*???m_pWebView;??
  • ????QGraphicsScene*?????m_pScene;??
  • ????External*???????????m_pExternal;??
  • };??
  • ??
  • #endif?//?MAINWINDOW_H??

  • MainWindow.cpp

    [cpp]?view plaincopy
  • #include?"mainwindow.h"??
  • ??
  • #include?<QWebFrame>??
  • #include?<QLayout>??
  • ??
  • MainWindow::MainWindow(QWidget?*parent)??
  • ????:?QGraphicsView(parent)??
  • {??
  • ????this->resize(?QSize(?800,?600)?);??
  • ??
  • ????m_pExternal?=?new?External();??
  • ??????
  • ????m_pScene?=?new?QGraphicsScene(this);??
  • ????if(NULL?!=?m_pScene)??
  • ????{??
  • ????????m_pWebView?=?new?QGraphicsWebView;??
  • ??
  • ????????if(?NULL?!=?m_pWebView)??
  • ????????{??
  • ????????????//enabled?javascript??
  • ????????????QWebSettings?*settings?=?m_pWebView->page()->settings();??
  • ??
  • ????????????settings->setAttribute(QWebSettings::JavascriptEnabled,true);????
  • ????????????settings->setAttribute(QWebSettings::JavascriptCanAccessClipboard,true);??
  • ????????????settings->setAttribute(QWebSettings::DeveloperExtrasEnabled,true);??
  • ????????????settings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls,?true);??
  • ????????????settings->setAttribute(QWebSettings::LocalContentCanAccessFileUrls,?true);??
  • ????????????settings->setAttribute(QWebSettings::JavascriptCanCloseWindows,?true);??
  • ????????????settings->setAttribute(QWebSettings::AutoLoadImages,true);??
  • ??
  • ????????????m_pScene->addItem(?m_pWebView?);??
  • ????????????this->setScene(?m_pScene?);??
  • ????????????connect(m_pWebView->page()->mainFrame(),?SIGNAL(javaScriptWindowObjectCleared()),??
  • ????????????this,?SLOT(AddJavascriptWindowObject()));??
  • ????????????m_pWebView->setUrl(QUrl("file:///Users/cblogs_code/QWebKitDemo/index.html"));??
  • ?????????}??
  • ????}???
  • }??
  • ??
  • MainWindow::~MainWindow()??
  • {??
  • ??
  • }??
  • ??
  • void?MainWindow::AddJavascriptWindowObject()??
  • {??
  • ????m_pWebView->page()->mainFrame()->addToJavaScriptWindowObject("external",?m_pExternal);??
  • }??

  • m_pWebView->setUrl(QUrl("file:///Users/cblogs_code/QWebKitDemo/index.html"));

    這一行是加載index.html,請(qǐng)嘗試的同學(xué)自行修改成自己的index.html的絕對(duì)路徑。

    當(dāng)網(wǎng)頁加載時(shí),會(huì)自動(dòng)觸發(fā)javaScriptWindowObjectCleared信號(hào),繼而我們的槽函數(shù)AddJavascriptWindowObject會(huì)被執(zhí)行,上面關(guān)于AddJavaScriptWindowObject解釋說:當(dāng)這個(gè)頁面析構(gòu)后,這個(gè)對(duì)象在js上下文中也將消失,監(jiān)聽到信號(hào)javaScriptWindowObjectCleared() 后來重新調(diào)用下addToJavaScriptWindowObject即可,因此,想讓external一直保持有效,這樣做就可以了。


    然后,運(yùn)行一下程序吧,點(diǎn)擊按鈕,你會(huì)看到如下結(jié)果:



    三. 調(diào)用QObject的方法

    js要調(diào)用已經(jīng)擴(kuò)展的對(duì)象external的方法,需要一下約束:
    1. 方法前需要Q_INVOKABLE修飾; 2. 方法返回值和參數(shù)必須是Qt內(nèi)置類型或者c++內(nèi)置類型,即使用typedef的也不行; 3. 方法返回值和參數(shù)可以是QObject*, 但參數(shù)不能傳遞js對(duì)象,傳js對(duì)象用QVariant代替。
    js中調(diào)用external的方法
    [html]?view plaincopy
  • var?ret?=?external.VerifyUserAccount("user01",?"123456");??
  • if?(ret?==?1)?{??
  • ?????alert("驗(yàn)證通過");??
  • ?}else?{??
  • ???????alert("用戶名或者密碼錯(cuò)誤");??
  • }??


  • 操作QObject對(duì)象的屬性

    這節(jié)我們來嘗試訪問一下External對(duì)象的msg屬性,并且修改TA,看看在Js層和C++層是否被修改。

    還是先看看測(cè)試頁面吧:

    [html]?view plaincopy
  • <!DOCTYPE?html?PUBLIC?"-//W3C//DTD?XHTML?1.0?Transitional//EN"?"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">??
  • <html?xmlns="http://www.w3.org/1999/xhtml">??
  • <head>??
  • <meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>??
  • <title>QWebKitDemo</title>??
  • <script?type="text/javascript">??
  • ??
  • window.onload?=?function(){??
  • ??
  • ????var?btnTest?=?document.getElementById("testCObj");??
  • ????btnTest.onclick?=?function()?{??
  • ????????alert(external);??
  • ????}??
  • ??
  • ????var?btnVisit?=?document.getElementById("visitProp");??
  • ????btnVisit.onclick?=?function()?{????????
  • ????????var?output?=?"js層面?\tmsg:?"+external.msg?+?"\n?c++層面?\tmsg:?"+external.GetPropMsg();??
  • ????????alert(output);??
  • ????}??
  • ??
  • ????var?btnSetProp?=?document.getElementById("setProp");??
  • ????btnSetProp.onclick?=?function()?{??
  • ????????var?tempValue?=?document.getElementById("msgProValue");??
  • ????????external.msg?=?tempValue.value;??
  • ????}??
  • }??
  • </script>??
  • </head>??
  • <body>??
  • ????<input?type="button"?id="testCObj"?value="測(cè)試C++對(duì)象">??
  • ????<p>測(cè)試屬性msg</p>??
  • ????<input?type="button"?id="visitProp"?value="visit">??
  • ????<input?type="text"?id="msgProValue"?value="修改后的msg">??
  • ????<input?type="button"?id="setProp"?value="修改">??
  • </body>??
  • </html>??

  • 運(yùn)行程序,我們先點(diǎn)擊visit按鈕,可以看到,顯示的msg屬性都是空值,然后再文本框中輸入字符,點(diǎn)擊修改按鈕,再點(diǎn)擊visit按鈕,試試看,彈出的msg是否有變化。


    四.?綁定QObject對(duì)象的信號(hào)/槽

    addJavaScriptWindowObject方法可以將對(duì)象的屬性、信號(hào)、槽統(tǒng)統(tǒng)映射到Js上下文中。
    綁定信號(hào)的方式如下

    [html]?view plaincopy
  • external.mouseClicked.connect(mouseClickedSlot);??
  • function?mouseClickedSlot()?{??
  • ????logger("mouse?clicked");??
  • }??

  • mouseClicked通過connect方法連接到j(luò)s的方法(槽),當(dāng)mouseClicked被觸發(fā)后,mouseClickedSlot將被執(zhí)行

    五. 為iframe添加QObject

    當(dāng)iframe被創(chuàng)建時(shí),mainFrame下的webpage的信號(hào)frameCreated會(huì)被觸發(fā); frameCreated的原型是: [cpp]?view plaincopy
  • void?frameCreated(QWebFrame*);??
  • 因此,我們可以為frameCreated關(guān)聯(lián)一個(gè)槽,在這個(gè)槽中,為新創(chuàng)建的QWebFrame添加QObject; 代碼如下: 1. 在MainWindow的構(gòu)造函數(shù)添加 [cpp]?view plaincopy
  • connect(this->m_pWebView->page(),?SIGNAL(frameCreated(QWebFrame*)),??
  • ????????????this,?SLOT(ChildFrameCreated(QWebFrame*)));??

  • 2. 為MainWindow類添加槽函數(shù) [cpp]?view plaincopy
  • public?slots:??
  • ????void?AddJavascriptWindowObject();??
  • ????void?ChildFrameCreated(QWebFrame?*frame);??

  • 3. 為MainWindow類添加如下實(shí)現(xiàn) [cpp]?view plaincopy
  • void?MainWindow::AddJavascriptWindowObject()??
  • {??
  • ????m_pWebView->page()->mainFrame()->addToJavaScriptWindowObject("external",?m_pExternal);??
  • }??
  • ??
  • void?MainWindow::AddJavascriptWindowObject(QWebFrame?*pFrame)??
  • {??
  • ????qDebug("AddJavascriptWindowObject");??
  • ????//add?external?object?to?main?web?frame??
  • ????pFrame->addToJavaScriptWindowObject("external",?m_pExternal);??
  • }??
  • ??
  • void?MainWindow::ChildFrameCreated(QWebFrame?*pFrame)??
  • {??
  • ????qDebug("ChildFrameCreated");??
  • ????if(pFrame?==?NULL)??
  • ????{??
  • ????????qDebug("Child?frame?created,?but?it?was?NULL!");??
  • ????}??
  • ????else??
  • ????{??
  • ????????AddJavascriptWindowObject(pFrame);??
  • ????}??
  • }??


  • 六. 總結(jié)

    到目前為止,一個(gè)Hybrid模式的應(yīng)用demo已經(jīng)完成了,我們來分析一下這種模式的優(yōu)劣;

    1、優(yōu)勢(shì):

    • 高效率開發(fā)UI豐富的應(yīng)用;
    • 底層框架可復(fù)用;
    • 可實(shí)現(xiàn)跨平臺(tái);
    • 其他好處……

    2、劣勢(shì):

    • 性能
    • 還是性能
    • 其他劣勢(shì)……

    隨著硬件的強(qiáng)大、html5的發(fā)展,不論是在pc端還是移動(dòng)端, 這種框架會(huì)得到普遍的認(rèn)可,i think so。

    猛戳下載代碼

    總結(jié)

    以上是生活随笔為你收集整理的[Qt] 利用QtWebKit完成JavaScript访问C++对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。