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是否都能实现

posted @ 2025-10-24 17:07  wuya178  阅读(139)  评论(0)    收藏  举报