qcefview库的使用
背景
调研在qt中使用web技术的几种方式,cef3可以单独升级谷歌内核。qcefview是封装了qt和web通信的库。
运行环境
qt5.15.2: qt4.8不支持的太多,qt5.9不支持用例里的随机数类等
vs2017: 2010内置的msvc编译器不支持c++11的Mutex等
qcefview: 2021年9月3日下的github最新的压缩包
chrome内核:cef_binary_89.0.12+g2b76680+chromium-89.0.4389.90_windows32
cmake:准备好代码和目录后直接运行自带的cmake脚本生成工程文件,直接编译成功没其他问题。
qcefview源码阅读
利用了qt元对象系统的反射技术。
qml中调用c++的方法也是一样的,c++注册函数为Q_INVOKABLE...
代码目录
除了chromium的源码外,这个项目代码量都不大,文件二三十个。
+--------------------------------------------------------------+
| QCefViewTest |
| 列举了几种通讯方式 |
| +----------------------------------------------------+ |
| | QCefView(windows) | |
| | 封装了对应QCefWindow的操作主要是QCefView类 | |
| | +-------------------------------------------+ | |
| | | CefViewCore(chromium):对chromium的操作封装 | | |
| | | 代码量不大,主要是CefViewBrowserHandler类. | | |
| | | 该类继承自CefClient,重载了浏览器ui操作 | | |
| | | | | |
| | +-------------------------------------------+ | |
| | | |
| +----------------------------------------------------+ |
| |
+--------------------------------------------------------------+
代码结构
Outline of QCefView:
+--------------------------------------------------------------+
| QCefView(QWidget) |
| |
| +----------------------------------------------------+ |
| | WindowWrapper(QWidget) | |
| | | |
| | +-------------------------------------------+ | |
| | | CefWindow(QWindow) | | |
| | | | | |
| | | | | |
| | | | | |
| | +-------------------------------------------+ | |
| | | |
| +----------------------------------------------------+ |
| |
+--------------------------------------------------------------+
Remarks:
The WindowWrapper and CefWindow are transparent to upper layer user.
列举的通讯方式
也可参考CSDN博文.
通讯方式一,widget中的函数通知web页面改变
//1、连接信号槽函数
connect(ui.btn_changeColor, SIGNAL(clicked()), this, SLOT(onBtnChangeColorClicked()));
//2、槽函数
QCefViewTest::onBtnChangeColorClicked()
{
cefview->changeColor();
}
//3、具体执行
void
CustomCefView::changeColor()
{
QColor color(0,0,0);
QCefEvent event("colorChange");//QCefView封装好的
event.setStringProperty("color", color.name());
broadcastEvent(event);
}
//4、Implementation实例(pImpl_)
bool
QCefView::broadcastEvent(const QCefEvent& event)
{
if (pImpl_)
return pImpl_->triggerEvent(event.objectName(), event, CefViewBrowserHandler::ALL_FRAMES);
return false;
}
//5、发送Event后js中改变主窗体背景色
function onColorChanged(event) {
var kvlist = [];
for (var key in event) {
kvlist.push(key + ":" + event[key])
}
alert(kvlist.join('\n'));
document.getElementById("main").style.backgroundColor = event["color"];
}
//跟到后面是进程间通讯了,还没看到添加listener的代码,onColorChanged是js中的函数名似乎没用
function onLoad() {
if (typeof (CallBridge) == 'undefined') {
return;
}
//addEventListener注意
CallBridge.addEventListener("colorChange", function (event) {
var kvlist = [];//下面这段for循环啥意思
for (var key in event) {
kvlist.push(key + ":" + event[key])
}
//alert(kvlist.join('\n'));
document.getElementById("main").style.backgroundColor = event["color"];
})
}
具体看看QCefEvent。
通讯方式二、鼠标拖拽事件
//1、js中的调用
function onDragAreaMouseDown() {
CallBridge.invokeMethod("onDragAreaMouseDown");
}
//2、c++直接在widget中响应这个函数,重载的函数
void
CustomCefView::onInvokeMethodNotify(int browserId, int frameId, const QString& method, const QVariantList& arguments)
{//等于这个方法函数时怎么响应
if (0 == method.compare("onDragAreaMouseDown")) {
#if defined(OS_WINDOWS)
HWND hWnd = ::GetAncestor((HWND)(this->window()->winId()), GA_ROOT);
// get current mouse cursor position
POINT pt;
::GetCursorPos(&pt);
// in case the mouse is being captured, try to release it
::ReleaseCapture();
// simulate that the mouse left button is down on the title area
::SendMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, POINTTOPOINTS(pt));
#endif
return;
} else if (
//3、CCefDelegate中调用
void
CCefDelegate::invokeMethodNotify(int browserId,
int frameId,
const std::string& method,
const CefRefPtr<CefListValue>& arguments)
//分发事件中的调用CefViewBrowserHandler为继承CefClient浏览器客户端
bool
CefViewBrowserHandler::DispatchNotifyRequest(CefRefPtr<CefBrowser> browser,
CefProcessId source_process,
CefRefPtr<CefProcessMessage> message)
通讯方式三、c++中invoke函数响应(两种UrlRequest、QueryRequest)
在CustomCefView类中使用了几种通讯方式,用了响应web UI的交互动作。都是采用invokeMethod函数的方式响应。实现跨线程或者跨进程的通讯,在web中调用qt的响应函数。
主要实现CustomCefView类定制的交互响应函数
//函数原型
bool QMetaObject::invokeMethod ( QObject * obj, const char * member, Qt::ConnectionType type, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument( 0 ), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument() ) [static]
具体为:
...
QMetaObject::invokeMethod(
this,
[=]() {
QString title("QCef InvokeMethod Notify");
QString text = QString("Current Thread: QT_UI\r\n"
"Method: %1\r\n"
"Arguments: ...")
.arg(method);
QMessageBox::information(this->window(), title, text);
},
Qt::QueuedConnection);
...
参数二member直接用匿名函数表示实现了,注意最后打印的线程ID为web ui线程。
UrlRequest简单直接调用invokeMethod
QueryRequest多了一点
QString response = query.reqeust().toUpper();
query.setResponseResult(true, response);
responseQCefQuery(query);
QCefView中定义的其他方法
QCefView::Implementation实例中的定义
void closeAllBrowsers()
void addLocalFolderResource(const QString& path, const QString& url)
void addArchiveResource(const QString& path, const QString& url, const QString& password)
void navigateToString(const QString& content)
void navigateToUrl(const QString& url)
bool browserCanGoBack()
bool browserCanGoForward()
void browserGoBack()
bool browserIsLoading()
void browserReload()
void browserStopLoad()
bool triggerEvent(const QString& name, const QCefEvent& event, int frameId = CefViewBrowserHandler::MAIN_FRAME)
bool responseQCefQuery(const QCefQuery& query)
void notifyMoveOrResizeStarted()
bool sendEventNotifyMessage(int frameId, const QString& name, const QCefEvent& event)
...
// create the browser,实现了很多chrome内核的原生接口
pQCefViewHandler_ = new CefViewBrowserHandler(pCefDelegate_);
CCefManager::getInstance().initializeCef();才是对CEF真正的初始化者
实践
D:\code\qcefview\QCefView-main\test\QCefViewTest
在此工程上修改使用重载 QCefView。
分两部分工作:
1、js前端框架jEasyUI开发的简单前端
2、js与qt通讯的粘合部分重载QCefView是否都能实现

浙公网安备 33010602011771号