什么是QCefView
QCefView 是为 Qt 开发的一个封装集成了CEF(Chromium Embedded Framework)库的Wdiget UI组件。使用QCefView可以充分发挥CEF丰富强大的Web能力,快速开发混合架构的应用程序。它不需要开发者理解CEF的细节,能够在Qt中更容易的使用CEF,发挥CEF的能力。
它可以将网页轻松嵌入到Qt QWidget中,以Qt的开发逻辑来使用它,同时提供了方便直观的 JavaScript 与 C++ 互交互能力。所以,我们甚至可以直接以web的方式编写UI界面。
编译QCefView
首先,下载QCefView源代码:
git clone --recursive https://github.com/CefView/QCefView.git
在编译之前,先进行一些配置,修改根目录的CMakeLists.txt
:
option(BUILD_DEMO "Build the demo" ON)
即将编译demo的选项打开
然后,设置Qt的路径,如果已将Qt设置为环境变量,则不用管。
修改QtConfig.cmake
set(QT_SDK_DIR
# Change this value to the Qt SDK path of your build environment
"D:/Qt/5.15.2/msvc2019_64"
)
修改Qt SDK 的路径,如这里的D:/Qt/5.15.2/msvc2019_64
Windows 平台编译
这里以 Clion IDE为例,介绍如何编译并运行QCefView的example
选中根目录的CMakeLists.txt
,右键使用Clion打开
注意,Clion打开之后,配置的时候,工具链需要选择Visual Studio
然后运行的时候,会自动下载CEF的二进制分发包,如果要指定CEF的分支或版本,可在CefViewCore/CefConfig.cmake
里修改。
注意,这里的格式为112.3.0+gb09c4ca+chromium-112.0.5615.165
,即将文件名cef_binary_112.3.0+gb09c4ca+chromium-112.0.5615.165_windows64
删除首尾的字符串。
同时,别忘了Clion配置需要选择QCefViewTest
Linux 平台编译
Linux平台可使用QtCreator打开CMakeLists.txt
,这里直接使用CMake命令演示:
在QCefView根目录下,打开终端,运行:
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build -j10
然后即可在QCefView/build/example/QCefViewTest/output/Debug/bin
路径下运行QCefViewTest程序
demo 讲解
这个QCefViewTest涉及的东西不少,依次讲解一番。
最左侧的这些按钮为Qt自带的控件:
Show Left DevTools
即打开左侧网页的的开发者工具
void
MainWindow::onBtnShowDevToolsClicked()
{
if (m_pLeftCefViewWidget) {
m_pLeftCefViewWidget->showDevTools();
}
}
Reload Right QCefView
右侧网页重新加载url,这里设置的是加载Google(国内打不开)
void
MainWindow::onBtnReloadRightViewClicked()
{
if (m_pRightCefViewWidget) {
m_pRightCefViewWidget->navigateToUrl("https://www.google.com");
}
}
Recreate Right QCefView
即重新加载右侧网页
void
MainWindow::onBtnRecreateRightViewClicked()
{
createRightCefView();
}
ChangeColor
生成随机颜色改变左侧网页的颜色,这里是通知网页端进行更改的
void
MainWindow::onBtnChangeColorClicked()
{
if (m_pLeftCefViewWidget) {
// create a random color
QColor color(QRandomGenerator::global()->generate());
// create the cef event and set the arguments
QCefEvent event("colorChange");
event.arguments().append(QVariant::fromValue(color.name(QColor::HexArgb)));
// broadcast the event to all frames in all browsers created by this QCefView widget
m_pLeftCefViewWidget->broadcastEvent(event);
}
}
// index.in.html
function onLoad() {
if (typeof CallBridge == "undefined") {
alert("Not in CefView context");
return;
}
CallBridge.addEventListener("colorChange", function (color) {
document.getElementById("main").style.backgroundColor = color;
});
}
SetFocus
设置左侧的焦点,可参考QWidget的setFocus()
CallJsCode
为执行JavaScript代码,这里是弹出一个alert的对话框。
void
MainWindow::onBtnCallJSCodeClicked()
{
QString context = "helloQCefView";
QString code = "alert('hello QCefView'); return {k1: 'str', k2: true, k3: 100};";
m_pLeftCefViewWidget->executeJavascriptWithResult(QCefView::MainFrameID, code, "", context);
}
NewBrowser
则是新建一个窗口
左侧网页
左侧网页为本地网页index.in.html
,有很多元素用来演示C++与JavaScript的交互,popup窗口、iframe等。
Web Area
演示可以通过网页实现窗口的拖拽移动,按住鼠标左键移动窗口。
Test Case for InvokeMethod
Invoke Method是Javascript通知C++端的演示,弹出的对话框就是由QMessageBox弹出的
function onInvokeMethodClicked(name, ...arg) {
CallBridge.invokeMethod(name, ...arg);
}
function testInvokeMethod() {
let d = {
d1: true,
d2: 5678,
d3: "test object",
d4: [1, "2", false],
d5: {
d1: true,
d2: 5678,
d3: "nested object",
d4: [1, "2", true],
},
};
onInvokeMethodClicked("TestMethod", 1, false, "arg3", d);
}
void
MainWindow::onInvokeMethod(int browserId, int64_t frameId, const QString& method, const QVariantList& arguments)
{
// extract the arguments and dispatch the invocation to corresponding handler
if (0 == method.compare("TestMethod")) {
QString title("QCef InvokeMethod Notify");
QString text = QString("================== Current Thread: QT_UI ==================\r\n"
"Frame: %1\r\n"
"Method: %2\r\n"
"Arguments:\r\n")
.arg(frameId)
.arg(method);
for (int i = 0; i < arguments.size(); i++) {
auto jv = QJsonValue::fromVariant(arguments[i]);
// clang-format off
text.append(
QString("%1 Type:%2, Value:%3\r\n")
.arg(i).arg(arguments[i].typeName()).arg(arguments[i].toString())
);
// clang-format on
}
auto jsonValue = QJsonDocument::fromVariant(arguments);
auto jsonString = QString(jsonValue.toJson());
text.append(QString("\r\nArguments List in JSON format:\r\n%1").arg(jsonString));
QMessageBox::information(this->window(), title, text);
} else {
}
}
Test Case for QCefQuery
演示将输入框里的内容发送给C++端
function onCallBridgeQueryClicked() {
var query = {
request: document.getElementById("message").value,
onSuccess: function (response) {
alert(response);
},
onFailure: function (error_code, error_message) {
alert(error_message);
},
};
window.CefViewQuery(query);
}
void
MainWindow::onQCefQueryRequest(int browserId, int64_t frameId, const QCefQuery& query)
{
QString title("QCef Query Request");
QString text = QString("Current Thread: QT_UI\r\n"
"Query: %1")
.arg(query.request());
QMessageBox::information(this->window(), title, text);
QString response = query.request().toUpper();
query.setResponseResult(true, response);
m_pLeftCefViewWidget->responseQCefQuery(query);
}
Test Case for Popup Browser
演示弹出两种popup窗口方式
<a href="#" target="_blank">Popup Browser By HTML</a>
<br />
<a href="#" onClick="window.open('#','QCefView Popup','width=800, height=600'); return false;">Popup Browser By Script</a>
An iframe with default borders
演示的是本地网页加载一个iframe页面,其余功能一致
右侧网页
右侧网页则是加载的在线网页
总结
至此,对于QCefView的编译及demo的功能讲解就结束了。由此可见QCefView的强大,与Web页面的交互能力,可以使得开发能更加的简便,也能使UI按照前端的逻辑设计成为可能。