Qt利用QWebEngineView,QWebChannel与JS通信
1、简单展示如何用QWebEngieView 显示百度网页
CccTestWebView.h
#ifndef CCCTESTWEBVIEW_H
#define CCCTESTWEBVIEW_H
#include <QWidget>
class QWebEngineView;
class CccTestWebView : public QWidget
{
Q_OBJECT
public:
explicit CccTestWebView(QWidget *parent = nullptr);
~CccTestWebView();
void initWidget();
private:
QWebEngineView* m_pWebView = nullptr;
};
#endif // FORM_H
CccTestWebView.cpp
#include "CccTestWebView.h"
#include <QWebEngineView>
#include <QVBoxLayout>
CccTestWebView::CccTestWebView(QWidget *parent)
:QWidget(parent)
{
initWidget();
}
CccTestWebView::~CccTestWebView()
{
}
void CccTestWebView::initWidget()
{
resize(420,680);
auto mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(0);
mainLayout->setMargin(0);
m_pWebView = new QWebEngineView(this);
m_pWebView->load(QUrl("http://www.baidu.com"));
mainLayout->addWidget(m_pWebView);
}
main.cpp
#include <QApplication>
#include "CccTestWebView.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CccTestWebView w;
w.show();
return a.exec();
}
结果
编译顺利的话你会正确的下显示百度的网页,如果报错看是不是事没有把webenginewidgets加入到.pro项目配置文件中去。但是此时你点击任何一个链接是不可以跳转到二级网页链接中去的。你需要自定义webengineview.
2、继承QWebEngineView,实现createWindow函数
CccWebEngineView.h
#ifndef CCCWEBENGINEVIEW_H
#define CCCWEBENGINEVIEW_H
#include <QObject>
#include <QWidget>
#include <QWebEngineView>
class CccWebEngineView : public QWebEngineView
{
Q_OBJECT
public:
explicit CccWebEngineView(QWidget* parent = nullptr);
~CccWebEngineView();
virtual QWebEngineView* createWindow(QWebEnginePage::WebWindowType type) override;
private:
QUrl m_url;
};
#endif // CCCWEBENGINEVIEW_H
CccWebEngineView.cpp
#include "CccWebEngineView.h"
CccWebEngineView::CccWebEngineView(QWidget *parent)
:QWebEngineView(parent)
{
//TODO: 链接hover时改变m_url的值
connect(this->page(), &QWebEnginePage::linkHovered, this, [this](const QString &url){
m_url.setUrl(url);
});
connect(this->page(), &QWebEnginePage::urlChanged, this, [this](const QUrl &url){
m_url = url;
});
}
CccWebEngineView::~CccWebEngineView()
{
}
QWebEngineView *CccWebEngineView::createWindow(QWebEnginePage::WebWindowType type)
{
Q_UNUSED(type);
if(!m_url.isEmpty())
{
this->load(m_url);//加载新的url
}
return nullptr;
}
CccTestWebView.h
#ifndef CCCTESTWEBVIEW_H
#define CCCTESTWEBVIEW_H
#include <QWidget>
class CccWebEngineView;
class CccTestWebView : public QWidget
{
Q_OBJECT
public:
explicit CccTestWebView(QWidget *parent = nullptr);
~CccTestWebView();
void initWidget();
private:
//QWebEngineView* m_pWebView = nullptr;
CccWebEngineView* m_pWebView = nullptr;
};
#endif // CCCTESTWEBVIEW_H
CccTestWebView.cpp
#include "CccTestWebView.h"
#include "CccWebEngineView.h"
#include <QWebEngineView>
#include <QVBoxLayout>
CccTestWebView::CccTestWebView(QWidget *parent)
:QWidget(parent)
{
initWidget();
}
CccTestWebView::~CccTestWebView()
{
}
void CccTestWebView::initWidget()
{
resize(420,680);
auto mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(0);
mainLayout->setMargin(0);
//m_pWebView = new QWebEngineView(this);
m_pWebView = new CccWebEngineView(this);//换成自实现的
m_pWebView->load(QUrl("http://www.baidu.com"));
mainLayout->addWidget(m_pWebView);
}
这时候就可以点击链接跳到相应的链接的页面去了
3、Qt如何跟JS之间进行互相通信呢?
CccJsContext.h
#ifndef CCCJSCONTEXT_H
#define CCCJSCONTEXT_H
#include <QObject>
#include <QtWebEngineWidgets/QWebEnginePage>
class CccJsContext : public QObject
{
Q_OBJECT
Q_PROPERTY(QString userId READ getUserId WRITE setUserId NOTIFY sigUserIdChange)
Q_PROPERTY(QString userToken READ getUserToken WRITE setUserToken NOTIFY sigUserTokenChange)
Q_PROPERTY(QString userInfo READ getUserInfo WRITE setUserInfo NOTIFY sigUserInfoChange)
public:
explicit CccJsContext(QObject *parent = nullptr);
void createConnections();
void setUserId(const QString& paramUserId);
QString getUserId()const;
void setUserToken(const QString& paramUserToken);
QString getUserToken()const;
void setUserInfo(const QString& paramUserInfo);
QString getUserInfo()const;
signals:
void sigUserIdChange();
void sigUserTokenChange();
void sigUserInfoChange();
public:
void sendMsg(QWebEnginePage* page, const QString& msg);
private:
QString userId = "123456";
QString userToken = "e9eo98kkkjj";
QString userInfo = "this is a test";
};
#endif // CccJsContext
CccJsContext.cpp
#include "CccJsContext.h"
#include <QDebug>
#include <string>
#include <QThread>
#include <QDir>
#include <QFileDialog>
CccJsContext::CccJsContext(QObject *parent)
:QObject(parent)
{
createConnections();
}
void CccJsContext::createConnections()
{
}
void CccJsContext::sendMsg(QWebEnginePage *page, const QString &msg)
{
page->runJavaScript(msg,[](const QVariant& v)
{
Q_UNUSED(v);
});
}
void CccJsContext::setUserId(const QString ¶mUserId)
{
userId = paramUserId;
emit sigUserIdChange();
}
QString CccJsContext::getUserId() const
{
return userId;
}
void CccJsContext::setUserToken(const QString& paramUserToken)
{
userToken = paramUserToken;
emit sigUserTokenChange();
}
QString CccJsContext::getUserToken()const
{
return userToken;
}
void CccJsContext::setUserInfo(const QString& paramUserInfo)
{
userInfo = paramUserInfo;
emit sigUserInfoChange();
}
QString CccJsContext::getUserInfo()const
{
return userInfo;
}
CccTestWebView.h CccTestWebView.cpp修改
#ifndef CCCTESTWEBVIEW_H
#define CCCTESTWEBVIEW_H
#include <QWidget>
class CccWebEngineView;
class QWebChannel;
class CccJsContext;
class CccTestWebView : public QWidget
{
Q_OBJECT
public:
explicit CccTestWebView(QWidget *parent = nullptr);
~CccTestWebView();
void initWidget();
private:
//QWebEngineView* m_pWebView = nullptr;
CccWebEngineView* m_pWebView = nullptr;
QWebChannel* m_pWebChannel = nullptr;
CccJsContext* m_pJsContext = nullptr;
};
#endif // CCCTESTWEBVIEW_H
#include "CccTestWebView.h"
#include "CccWebEngineView.h"
#include "CccJsContext.h"
#include <QWebEngineView>
#include <QVBoxLayout>
#include <QWebChannel>
CccTestWebView::CccTestWebView(QWidget *parent)
:QWidget(parent)
{
initWidget();
}
CccTestWebView::~CccTestWebView()
{
}
void CccTestWebView::initWidget()
{
resize(420,680);
auto mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(0);
mainLayout->setMargin(0);
//m_pWebView = new QWebEngineView(this);
m_pWebView = new CccWebEngineView(this);
m_pWebChannel = new QWebChannel(this);
m_pJsContext = new CccJsContext(this);
m_pWebChannel->registerObject("CccJsBridge", m_pJsContext);
m_pWebView->page()->setWebChannel(m_pWebChannel);
QString htmlPath = "file:///";
htmlPath.append("/Users/myname/Desktop/htmltest/test.html");
m_pWebView->load(QUrl(htmlPath));
//Qt调用js函数例子
//QString jsFun = "QtCallJsFun()";
//m_pJsContext->sendMsg(m_pWebView->page(),jsFun);
mainLayout->addWidget(m_pWebView);
}
结果
test.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script src = "js/qwebchannel.js" type="text/javascript"></script>
<script src = "js/msgutils.js" type="text/javascript"></script>
</head>
<body>
<div id="app" style="width: 195px;height: 175px;">
</div>
<button onclick="getUserId()">获取用户Id</button>
<button onclick="getUserToken()">获取用户Token</button>
<button onclick="getUserInfo()">获取用户信息(json)</button>
</body>
<script type="text/javascript">
function getUserId()
{
var userId = CccJsBridge.userId;
alert("userId:" + userId);
}
function getUserToken()
{
var userToken = CccJsBridge.userToken;
alert("userToken:" + userToken);
}
function getUserInfo()
{
var jsonUserInfo = CccJsBridge.userInfo;
var userInfoObj = JSON.parse(jsonUserInfo);
//判null
alert("userId:" + userInfoObj.userId + " userToken:" + userInfoObj.userToken);
}
</script>
在这个Demo里面JS是通过同步的方式获取C++中CccJsBridge中的值的,也可以通过在CccJsContext加上槽函数给JS调用
qwebchannel.js 在Qt安装目录下搜索找下
msgutls.js代码为
var CccJsBridge;
function init()
{
if (typeof qt != 'undefined')
{
new QWebChannel(qt.webChannelTransport, function(channel)
{
CccJsBridge = channel.objects.CccJsBridge;
}
);
}
else
{
alert("qt对象获取失败!");
}
}
// 向qt发送消息
function sendMessage(msg)
{
if(typeof CccJsBridge == 'undefined')
{
alert("context对象获取失败!");
}
else
{
CccJsBridge.onMsg(msg);
}
}
// 控件控制函数
function onBtnSendMsg()
{
var cmd = document.getElementById("待发送消息").value;
sendMessage(cmd);
}
function recvMessage(msg)
{
alert("接收到Qt消息:" + msg);
}
init();