一、支持功能
1.1、加载网页,加载本地html文件(暂不支持js交互)
1.2、点击页面跳转
1.3、F5刷新、F12调试器
1.4、ctrl+滚轮滑动改变页面大小
1.5、滚轮滑动页面联动
1.6、js和C++互相调用(页面放大/缩小显示放大比例)
二、源代码
main.cpp
#include <iostream>
#include <QApplication>
#include "WebviewImpl.h"
#include "Path.h"
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
WebviewImpl view;
{
// local file, prefix: file:/ + source
std::string strSourcePath = "file:/" + Utils::GetSourcePath() + "js_test/html/test.html";
//view.load(QUrl("https://www.qt.io/"));
//view.load(QUrl(strSourcePath.c_str()));
view.load(QUrl("http://www.baidu.com"));
view.show();
}
int nCode = a.exec();
// do something(uninit)
return nCode;
}
Path.h
#pragma once
#include <string>
#include <direct.h>
#include <fstream>
namespace Utils
{
const int kMaxPath = 260;
static std::string GetSourcePath()
{
char szPath[kMaxPath] = { 0 };
_getcwd(szPath, kMaxPath);
std::string strSourcePath(szPath);
if(strSourcePath.back() != '\\' || strSourcePath.back() != '\/')
strSourcePath += "/";
return strSourcePath;
}
static bool IsFileExist(const std::string& strFile)
{
bool bExist = false;
std::fstream fin(strFile, std::ios::in);
if(fin.is_open())
{
bExist =true;
fin.close();
}
return bExist;
}
}
WebviewImpl.h
#pragma once
#include <QWebView>
#include <QKeyEvent>
class QWebInspector;
class WebviewImpl : public QWebView
{
Q_OBJECT
public:
WebviewImpl();
~WebviewImpl();
void CallJs(const QString& qstrInfo);
protected:
QWebView* createWindow(QWebPage::WebWindowType type) override;
void keyPressEvent(QKeyEvent*) override;
void keyReleaseEvent(QKeyEvent*) override;
void wheelEvent(QWheelEvent*) override;
private slots:
void onLoadFinished(bool bFinished);
void onLoadProgress(int nProgress);
void onTitleChanged(const QString& qstrTitle);
void onIconChanged();
void onUrlChanged(const QUrl&);
void onLoadUrl(const QUrl&);
private:
void init_signals();
private:
QWebInspector* m_pInspector;
bool m_bCtrlPressed;
};
WebviewImpl.cpp
#include "WebviewImpl.h"
#include <QDebug>
#include <QWebInspector>
#include <QWebFrame>
#include "JsHelper.h"
WebviewImpl::WebviewImpl()
: QWebView(nullptr)
, m_pInspector(nullptr)
, m_bCtrlPressed(false)
{
init_signals();
// close window will invoke destruct function, it'll crash while support debugger
//setAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_TranslucentBackground);
//setWindowFlags(Qt::FramelessWindowHint);// | Qt::WindowStaysOnTopHint);
QWebSettings* settings = this->settings();
//settings->setAttribute(QWebSettings::PluginsEnabled, true);
settings->setAttribute(QWebSettings::JavaEnabled, true);
settings->setAttribute(QWebSettings::JavascriptEnabled, true);
//settings->setAttribute(QWebSettings::JavascriptCanOpenWindows, true);
//settings->setAttribute(QWebSettings::JavascriptCanAccessClipboard, true);
// debugger window(F12)
settings->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
//settings->setAttribute(QWebSettings::SpatialNavigationEnabled, true);
//settings->setAttribute(QWebSettings::LinksIncludedInFocusChain, true);
//settings->setAttribute(QWebSettings::AcceleratedCompositingEnabled, true);
//settings->setAttribute(QWebSettings::AutoLoadImages, true);
setContextMenuPolicy(Qt::NoContextMenu); // disable menu with mouse right click
}
WebviewImpl::~WebviewImpl()
{
if (m_pInspector != nullptr)
{
delete m_pInspector;
m_pInspector = nullptr;
}
}
void WebviewImpl::CallJs(const QString& qstrInfo)
{
page()->mainFrame()->evaluateJavaScript(qstrInfo);
}
/***************************************************************************************************
* override *
****************************************************************************************************/
QWebView* WebviewImpl::createWindow(QWebPage::WebWindowType type)
{
// create a new webview for click
WebviewImpl* pView = new WebviewImpl();
connect(pView, SIGNAL(urlChanged(const QUrl&)), this, SLOT(onLoadUrl(const QUrl&)));
return pView;
}
void WebviewImpl::keyPressEvent(QKeyEvent* pEvent)
{
switch (pEvent->key())
{
case Qt::Key_F5: // F5
{
this->reload();
break;
}
case Qt::Key_F12: // F12
{
if (nullptr == m_pInspector)
{
m_pInspector = new QWebInspector(/*this*/);
m_pInspector->setWindowFlags(Qt::WindowStaysOnTopHint | Qt::Dialog);
m_pInspector->setMinimumSize(500, 300);
m_pInspector->setPage(this->page());
//m_pInspector->setAttribute(Qt::WA_DeleteOnClose);
}
m_pInspector->show();
qDebug() << "F12 pressed";
break;
}
case Qt::Key_Control: // ctrl pressed
{
m_bCtrlPressed = true;
break;
}
default:
break;
}
QWebView::keyPressEvent(pEvent);
}
void WebviewImpl::keyReleaseEvent(QKeyEvent* pEvent)
{
switch (pEvent->key())
{
case Qt::Key_Control: // ctrl released
{
m_bCtrlPressed = false;
break;
}
default:
break;
}
QWebView::keyReleaseEvent(pEvent);
}
void WebviewImpl::wheelEvent(QWheelEvent* pEvent)
{
int nDelta = pEvent->delta();
if (m_bCtrlPressed)
{
// ctrl + wheel
if (nDelta > 0) // up
{
this->setZoomFactor(this->zoomFactor() + 0.1);
}
else
{
this->setZoomFactor(this->zoomFactor() - 0.1);
}
QString qstrInfo = QString("UpdateInfo('Factor %1%')").arg(this->zoomFactor() * 100);
CallJs(qstrInfo);
}
else
{
QPoint ptScroll = this->page()->mainFrame()->scrollPosition();
if (ptScroll.y() < 0) return; // filter the invalid value
// handle wheel for view
ptScroll.setY(ptScroll.y() - nDelta);
this->page()->mainFrame()->setScrollPosition(ptScroll);
}
QWebView::wheelEvent(pEvent);
}
/***************************************************************************************************
* slots *
****************************************************************************************************/
void WebviewImpl::onLoadFinished(bool bFinished)
{
qDebug() << "Load state: " << bFinished;
if (bFinished)
{
this->page();
this->setWindowIcon(this->icon());
// js interactive
this->page()->mainFrame()->addToJavaScriptWindowObject("view", &JsHelper::Instance());
QWebSettings::clearMemoryCaches();
QWebSettings::clearIconDatabase();
}
}
void WebviewImpl::onLoadProgress(int nProgress)
{
//qDebug() << "Load progress: " << nProgress;
}
void WebviewImpl::onTitleChanged(const QString& qstrTitle)
{
if (qstrTitle.isEmpty()) return;
qDebug() << "Title changed: " << qstrTitle;
this->setWindowTitle(qstrTitle);
}
void WebviewImpl::onIconChanged()
{
// don't invoke forever, genius
qDebug() << "Ico changed: ";
}
void WebviewImpl::onUrlChanged(const QUrl& url)
{
qDebug() << "Url changed: " << url;
}
void WebviewImpl::onLoadUrl(const QUrl& url)
{
load(url);
}
/***************************************************************************************************
* private funciton *
****************************************************************************************************/
void WebviewImpl::init_signals()
{
bool bSucc = false;
connect(this, SIGNAL(loadFinished(bool)), this, SLOT(onLoadFinished(bool)));
connect(this, SIGNAL(loadProgress(int)), this, SLOT(onLoadProgress(int)));
connect(this, SIGNAL(urlChanged(const QUrl&)), this, SLOT(onUrlChanged(const QUrl&)));
connect(this, SIGNAL(titleChanged(const QString&)), this, SLOT(onTitleChanged(const QString&)));
bSucc = connect(this, SIGNAL(iconChanged()), this, SLOT(onIconChanged()));
//connect(page()->mainFrame(), SIGNAL(loadFinished(bool)), SLOT(onLoadFinished(bool)));
//qDebug() << "Connect state: " << bSucc;
}
JsHelper.h
#pragma once
#include <QObject>
#include "Singleton.h"
class JsHelper : public QObject, public Singleton<JsHelper>
{
friend class Singleton<JsHelper>;
Q_OBJECT
public:
JsHelper(QWidget* parent = nullptr);
~JsHelper();
public slots:
// js invoke, it must public slots
void onShowJsInfo(const QString& qstrInfo);;
};
JsHelper.cpp
#include "JsHelper.h"
#include <QDebug>
JsHelper::JsHelper(QWidget* parent/* = nullptr*/)
{
}
JsHelper::~JsHelper()
{
}
/***************************************************************************************************
* js functions *
****************************************************************************************************/
void JsHelper::onShowJsInfo(const QString& qstrInfo)
{
qDebug() << "JS called, info: " << qstrInfo;
}
test.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>JavaScript 调用 C++ 函数</title>
<script>
function CallCppFunc() {
var info = document.getElementById("txtInfo").value;
if (info == "") {
alert("请输入要发送给 C++ 的数据!");
return;
}
view.onShowJsInfo(info);
}
function UpdateInfo(info) {
//alert("invoke");
var show_info = document.getElementById("txtInfo");
show_info.value=info;
}
</script>
</head>
<body>
<input id="txtInfo" type="text" />
<button id="btnCallCppFunc" onclick="CallCppFunc();">调用 C++ 函数</button>
</body>
</html>
三、扫坑
QSslSocket: cannot call unresolved function
Solve:***将系统的ssleay32.dll和ssleay32.dll到qt的bin目录***