您现在的位置是:网站首页> C/C++

Qt浏览器相关编程收集

  • C/C++
  • 2024-12-15
  • 1152人已阅读
摘要

Qt浏览器相关编程收集


Qt加载QWebEngineView和js交互

VS中添加QWebEngineVie模块

Qt使用miniblink

QT5.5老版本使用webview

QT使用webengineview



Qt加载QWebEngineView和js交互

Qt5之后竟然集成了chromium;测试验证技术是否可用,目前除了http音频无法播放,CPP和JS交互,包括网页调试,已完全OK;顺便吐槽一下“百度”,搜的都是一样,多少都少点东西,不是缺 qwebchannel.js 就是少了jquery-3.1.1.min.js,一般情况下肯定在本地调试! 少了jquery,本地测试js无法调用Qt提供的方法(也是公共槽的方法);

点击下载qwebchannel

下面是主要代码 和 注意事项:


       1.必须加载qwebchannel.js, 如果是本地调试还需要jquery-3.1.1.min.js;


       2.打开本地调试:http://127.0.0.1:9999(Remote debugging server started successfully. Try pointing a Chromium-based browser to http://127.0.0.1:9999)


定义更新属性:


          


#ifndef JSCPP_H

#define JSCPP_H


#include <QObject>

#include <QMessageBox>


class JsCpp : public QObject

{undefined

    Q_OBJECT


    Q_PROPERTY(QString name MEMBER m_name NOTIFY sigNameChanged)

    Q_PROPERTY(int age MEMBER m_age NOTIFY sigAgeChanged)


public:

    JsCpp(QObject *parent = 0);

    ~JsCpp();


public:

    void SetName(const QString name);

    void SetAge(const int age);


public slots:

    void ShowMsg(const QString& param1, const QString& param2);


signals:

    void sigNameChanged(const QString& name);

    void sigAgeChanged(int age);


private:

    QString m_name;

    int m_age;

};


#endif // JSCPP_H、


//>>>>>>>>>>>>>>>>>>......提供方法....的文件....................


#include "JsCpp.h"


JsCpp::JsCpp(QObject *parent)

    : QObject(parent)

{undefined

    m_name = "a_hua";

    m_age = 16;


}


JsCpp::~JsCpp()

{undefined


}


void JsCpp::SetName(const QString name)

{undefined

    m_name = name;


    emit sigNameChanged(name);

}

void JsCpp::SetAge(const int age)

{undefined

    m_age = age;


    emit sigAgeChanged(age);

}


void JsCpp::ShowMsg(const QString& param1, const QString& param2)

{undefined

    QMessageBox::information(nullptr, "Hello " + param1, "I'm here! " + param2, QMessageBox::Ok);

}


 


///主类中的方法///


####构造 ---- 初始化------

    //打开调试..

    qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "9999");


    m_pWebView = new QWebEngineView(ui.widget);//

    connect(m_pWebView, SIGNAL(loadFinished(bool)), this, SLOT(webLoadFinished(bool)));


    //打开本地缓存.

    QString _strStoreage = QString("%1/local_storage").arg(QCoreApplication::applicationDirPath());

    QDir _dir(_strStoreage);

    if (!_dir.exists())

        _dir.mkpath(_strStoreage);

    m_pWebView->page()->profile()->setPersistentStoragePath(_strStoreage);


    //提供的方法类

    m_pJsCpp = new JsCpp();


    //创建。。。。。。调用......

    m_pWebChannel = new QWebChannel();

    m_pWebChannel->registerObject("js_cpp", m_pJsCpp);//注册对象

    //必须设置,否则无法调用方法....

    m_pWebView->page()->setWebChannel(m_pWebChannel);

    

    //加载页面

    QString _testPath = QString("%1/HtmlTest/test.html").arg(QCoreApplication::applicationDirPath());

    m_pWebView->load(QUrl(_testPath));、


 


###调用js


m_pWebView->page()->runJavaScript("showMessage()");


 


==================测试页面=====================


<!DOCTYPE html>

<html>

<head>

    <title>测试页面</title>

    <script type="text/javascript" src="./jquery-3.1.1.min.js"></script>

    <script type="text/javascript" src="./qwebchannel.js"></script>

    <meta charset="utf-8" />

    <div>

        <span>name:</span><input type="text" id="name"/>

        <br/>

        <span>age:</span><input type="text" id="age"/>

    </div>

</head>

<body bgcolor="#c1d1d1">

    <input type="button" value="Click" οnclick="showMessage()" ID="Button">

    <input type="button" value="QtMethod" οnclick="showMessage()" ID="Button">

</body>

    <script>

       function showMessage()

       {undefined

          QtCpp.ShowMsg("111", "2222");

       }

       var updateName = function(text)

       {undefined

            $("#name").val(text);

       }

       var updateAge = function(text)

       {undefined

             $("#age").val(text);

       }

      new QWebChannel(qt.webChannelTransport, function(channel){undefined

        var _obj = channel.objects.js_cpp;

        window.QtCpp = _obj;

        

        updateName(_obj.name);

        updateAge(_obj.age);

        

        _obj.sigNameChanged.connect(updateName);

        _obj.sigAgeChanged.connect(updateAge);

      });

    </script>

</html>



VS中添加QWebEngineVie模块

开发环境: Qt 5.7.0 VS2015


VS2015 在生成新的工程时,会默认带了一些模块。

如果添加新的模块如何操作呢?

目前就添加 [QWebEngineView] 模块为例。



在生成新的工程时默认带的模块:

图一

1.png


第一步:

代码中添加 [QWebEngineView] 代码 然后编译

代码1


#include <QtWidgets/QMainWindow>

#include "ui_qttest001.h"

#include <QWebEngineView>

 

class QtTest001 : public QMainWindow

{

Q_OBJECT

 

public:

QtTest001(QWidget *parent = 0);

~QtTest001();

 

void resizeEvent(QResizeEvent*);

 

private:

Ui::QtTest001Class ui;

QWebEngineView* view;

};

 

#endif // QTTEST001_H


代码2

#include "qttest001.h"

 

QtTest001::QtTest001(QWidget *parent)

: QMainWindow(parent)

{

ui.setupUi(this);

 

view = new QWebEngineView(this);

view->load(QUrl("https://www.baidu.com/"));

view->show();

}

 

QtTest001::~QtTest001()

{

 

}

 

void QtTest001::resizeEvent(QResizeEvent*)

{

view->resize(this->size());

}



当编译出现错误:

如图2

2.png


此问题是没添加 WebEngineView 文件路径

$(QTDIR)\include\QtWebEngineWidgets


按照下图的步骤添加WebEngineView 就可以啦

图3

3.png



图4

4.png


第二步: 添加lib 库文件

Qt5WebEngined.lib

Qt5WebEngineWidgetsd.lib

图5

5.png


然后编译运行。


Qt使用miniblink

用Qt做项目过程中,遇到需要用到浏览器控件的项目,可能都会绕不开一个问题,那就是从Qt5.6版本开始mingw编译器的Qt构建套件,不再提供浏览器控件了,之前还可以用webkit控件,这下很多项目要么选择5.6以下版本,要么选择msvc的构建套件,而且大部分的msvc构建套件还不自带浏览器控件,也需要自己编译,只有原配的构建套件比如Qt5.9+VS2015、Qt5.12+VS2017这种搭配才可能有浏览器控件,不然就算你勾选了浏览器控件也不会安装,这样就使得很多依赖浏览器控件的项目比较被动,于是必须寻找一个轻量级的浏览器控件来替代,比如cef、miniblink,个人更倾向于miniblink,用法极其简单,依赖极其精简就一个dll,在linux和mac系统上本来qt就一直会有浏览器控件,所以也就不涉及到跨平台的问题,所以miniblink暂支持windows的缺点也就不算缺点了。


miniblink是一个追求极致小巧的浏览器内核项目,全世界第三大流行的浏览器内核控件。其基于chromium最新版内核,去除了chromium所有多余的部件,只保留最基本的排版引擎blink。miniblink保持了10M左右的极简大小,是所有同类产品最小的体积,同时支持windows


qt+miniblink用法步骤:


- 第一步:调用wkeSetWkeDllPath函数加载dll文件路径,一个项目只需要执行一次。


- 第二步:调用wkeInitialize初始化动态库,一个项目只需要执行一次。


- 第三步:调用wkeCreateWebWindow创建一个浏览器控件,传入句柄。


- 第四步:调用wkeOnLoadingFinish注册回调加载完成信号,有需要才注册。


- 第五步:调用wkeJsBindFunction注册回调接收数据的方法,一定要放在这里在网页加载前执行。


- 第六步:调用wkeLoadURL加载网址、wkeLoadFile加载网页文件、wkeLoadHtmlWithBaseUrl加载网页内容。


- 第七步:调用wkeRunJS执行js函数,超级简单。


- 第八步:调用wkeFinalize释放资源,只要执行一次,在整个项目结束的时候。


qt+miniblink完整demo开源地址:


https://gitee.com/feiyangqingyun/QWidgetDemo/tree/master/miniblink


https://github.com/feiyangqingyun/QWidgetDemo/tree/master/miniblink


相关代码

#ifndef MINIBLINK_H

#define MINIBLINK_H


#include <QWidget>

#include "wke.h"


class miniblink : public QWidget

{

    Q_OBJECT

public:

    explicit miniblink(QWidget *parent = 0);


    //初始化资源

    static void init();

    //释放资源

    static void release();


protected:

    //设置浏览器控件自动适应大小

    void resizeEvent(QResizeEvent *);


private:

    //浏览器控件对象

    wkeWebView webView;


signals:

    //网页载入完成

    void loadFinished(bool ok);

    //收到网页发出来的数据

    void receiveDataFromJs(const QString &type, const QVariant &data);


public:

    //给回调用的函数

    void loadFinish(bool ok);

    void receiveData(const QString &type, const QVariant &data);


public slots:

    //加载网址或者本地文件

    void load(const QString &url, bool file = false);

    //加载html内容

    void setHtml(const QString &html, const QString &baseUrl);

    //执行js函数

    void runJs(const QString &js);

};


#endif // MINIBLINK_H

#include "miniblink.h"

#include "qapplication.h"

#include "qdebug.h"


void onLoadingFinish(wkeWebView, void *param, const wkeString, wkeLoadingResult result, const wkeString)

{

    //qDebug() << "onLoadingFinish" << result;

    //在注册函数的地方就已经传入了类指针

    miniblink *widget = (miniblink *)param;

    //0 = WKE_LOADING_SUCCEEDED, 1 = WKE_LOADING_FAILED, 2 = WKE_LOADING_CANCELED

    widget->loadFinish(result == 0);

}


jsValue WKE_CALL_TYPE objName_receiveData(jsExecState es, void *param)

{

    if (0 == jsArgCount(es)) {

        return jsUndefined();

    }


    //挨个取出参数,设定的通用方法,只有两个参数

    jsValue arg0 = jsArg(es, 0);

    jsValue arg1 = jsArg(es, 1);

    if (!jsIsString(arg0)) {

        return jsUndefined();

    }


    //在注册函数的地方就已经传入了类指针

    miniblink *widget = (miniblink *)param;

    QString type = QString::fromStdString(jsToString(es, arg0));

    QVariant data = QString::fromStdString(jsToString(es, arg1));

    widget->receiveData(type, data);

    return jsUndefined();

}


miniblink::miniblink(QWidget *parent) : QWidget(parent)

{

    //第一步先初始化动态库

    init();

    //第二步初始化浏览器控件

    //创建一个浏览器控件,放入句柄

    webView = wkeCreateWebWindow(WKE_WINDOW_TYPE_CONTROL, (HWND)this->winId(), 0, 0, this->width(), this->height());

    //关联完成信号

    wkeOnLoadingFinish(webView, onLoadingFinish, this);

    //设置浏览器控件可见

    wkeShowWindow(webView, TRUE);

    //注册通用的接收数据的方法,一定要放在这里在网页加载前执行

    wkeJsBindFunction("objName_receiveData", objName_receiveData, this, 2);

}


void miniblink::init()

{

    //全局只需要初始化一次

    static bool isInit = false;

    if (!isInit) {

        isInit = true;

        //不同的构建套件位数加载不同的动态库

#ifdef Q_OS_WIN64

        QString file = qApp->applicationDirPath() + "/miniblink_64.dll";

#else

        QString file = qApp->applicationDirPath() + "/miniblink.dll";

#endif

        const wchar_t *path = reinterpret_cast<const wchar_t *>(file.utf16());

        wkeSetWkeDllPath(path);

        bool ok = wkeInitialize();

        qDebug() << QString("init miniblink %1").arg(ok ? "ok" : "error");

    }

}


void miniblink::release()

{

    wkeFinalize();

}


void miniblink::resizeEvent(QResizeEvent *)

{

    wkeResize(webView, this->width(), this->height());

}


void miniblink::loadFinish(bool ok)

{

    emit loadFinished(ok);

}


void miniblink::receiveData(const QString &type, const QVariant &data)

{

    emit receiveDataFromJs(type, data);

}


void miniblink::load(const QString &url, bool file)

{

    const char *temp = url.toLocal8Bit().data();

    if (file) {

        wkeLoadFile(webView, temp);

    } else {

        wkeLoadURL(webView, temp);

    }

}


void miniblink::setHtml(const QString &html, const QString &baseUrl)

{

    wkeLoadHtmlWithBaseUrl(webView, html.toLocal8Bit().data(), baseUrl.toLocal8Bit().data());

}


void miniblink::runJs(const QString &js)

{

    wkeRunJS(webView, js.toLocal8Bit().data());

}


C++调用JavaScript

和wke一样,wkexe也可以通过相同的wkeRunJS函数调用JavaScript代码,但不同的是,如果C++代码想要获得JavaScript的返回值,需要在调用的JS代码前加上return:


jsRet = wkeRunJS(gWkeWebView, "return funcforcplusplus(\"\xe4\xbd\xa0\xe5\xa5\xbd ABCDEFG\")");

jsRetStr = jsToStringW(wkeGlobalExec(gWkeWebView), jsRet);

MessageBox(hWnd, jsRetStr, L"runJS返回", 0);


JavaScript调用C++

同wke一样,JS调用C++代码也需要绑定,在RunApplication函数中CreateWebWindow之前添加如下代码:


jsBindFunction("msgBox", js_msgBox, 2);//JS调用C++

1

同时在app.cpp文件中添加:


//JS调用C++

jsValue JS_CALL js_msgBox(jsExecState es)

{

    const wchar_t* text = jsToStringW(es, jsArg(es, 0));

    const wchar_t* title = jsToStringW(es, jsArg(es, 1));

    MessageBox(NULL, text, title, 0);

    return jsStringW(es, L"C++返回字符串");


}

这里有个BUG需要注意,miniblink的jsToStringW函数目前只能处理JavaScript传入的字符串参数(作者将在下步更新代码时修正),如果前端msgBox函数传入的参数不是字符串类型,那么会得到空值

附上前端测试用的HTML代码如下:


<!DOCTYPE html>

<html xmlns="/1999/xhtml">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>WKE Test Web Page</title>

<script>

function funcforcplusplus(instr){

    document.getElementById('result').value=instr;

    return navigator.userAgent;

    //return "JavaScript Return 返回啦";

}

</script>

</head>

<body>

<p>WKE Test Web Page</p>

<a href='#' onclick="document.getElementById('result').value=msgBox('TEST Function from JS to Cpp','来自Javascript的调用');">LINK</a>

<textarea rows='6' cols='36' id='result'>hello</textarea>

</body>

</html>


QT5.5老版本使用webview

.pro添加  

QT       += core gui webkitwidgets

添加头文件

#include <QtWebKitWidgets/QWebView>



QT使用webengineview

可能是由于内容开始是网络地址(http://...)完整的英文词截取后不能换行造成 为避免代码造成手机端排版的混乱,可适当增加文字描述,将代码往后推移

添加Debug需要的库:qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgets.lib;Qt5WebViewd.lib;Qt5WebEngineWidgetsd.lib;%(AdditionalDependencies)

包含的目录

.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)

1.png

2.png

附加库目录:$(QTDIR)\lib;%(AdditionalLibraryDirectories)

3.png






Top