离屏渲染(Off-Screen Rendering)
在离屏渲染模式下,CEF不会创建原生浏览器窗口。CEF为宿主程序提供无效的区域和像素缓存区,而宿主程序负责通知鼠标键盘以及焦点事件给CEF。离屏渲染目前不支持混合加速,所以性能上可能无法和非离屏渲染相比。离屏浏览器将收到和窗口浏览器同样的事件通知,
下面介绍如何使用离屏渲染:
实现CefRenderHandler接口。除非特别说明,所有的方法都需要覆写。
调用CefWindowInfo::SetAsOffScreen(),将CefWindowInfo传递给CefBrowserHost::CreateBrowser()之前还可以选择设置CefWindowInfo::SetTransparentPainting()。如果没有父窗口被传递给SetAsOffScreen,则有些类似上下文菜单这样的功能将不可用。
CefRenderHandler::GetViewRect方法将被调用以获得所需要的可视区域。
CefRenderHandler::OnPaint() 方法将被调用以提供无效区域(脏区域)以及更新过的像素缓存。cefclient程序里使用OpenGL绘制缓存,但你可以使用任何别的绘制技术。
可以调用CefBrowserHost::WasResized()方法改变浏览器大小。这将导致对GetViewRect()方法的调用,以获取新的浏览器大小,然后调用OnPaint()重新绘制。
调用CefBrowserHost::SendXXX()方法通知浏览器的鼠标、键盘和焦点事件。
调用CefBrowserHost::CloseBrowser()销毁浏览器。
使用命令行参数–off-screen-rendering-enabled运行cefclient,可以测试离屏渲染的效果。
离屏渲染可以Qt背景透明下的显示问题,比如做一些异形窗口。
我们从一个简单的例子来实现Qt中的Cef3的离屏渲染。上面的步骤看起来有点复杂,但我们从实际的例子入手,一步步完善,就简单了。
第一步:
在CefSettings中的windowless_rendering_enabled设置为true
settings.windowless_rendering_enabled = true;
第二步:
继承CefRenderHandler,并且实现它全部接口(也就是纯虚函数),和重新部分virtual函数(是部分,可以不用全部实现,这个看你的功能需求)
// Called to retrieve the view rectangle which is relative to screen
// coordinates. This method must always provide a non-empty rectangle.
///
/*--cef()--*/
virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) = 0;
// Called when an element should be painted. Pixel values passed to this
// method are scaled relative to view coordinates based on the value of
// CefScreenInfo.device_scale_factor returned from GetScreenInfo. |type|
// indicates whether the element is the view or the popup widget. |buffer|
// contains the pixel data for the whole image. |dirtyRects| contains the set
// of rectangles in pixel coordinates that need to be repainted. |buffer| will
// be |width|*|height|*4 bytes in size and represents a BGRA image with an
// upper-left origin. This method is only called when
// CefWindowInfo::shared_texture_enabled is set to false.
///
/*--cef()--*/
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width,
int height) = 0;
解释一下:
virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) = 0;
这个纯虚函数就是获取浏览器的矩形范围,想象一下,如果你想将浏览器放在某个QWidget,或者子控件上,那么这里的rect就应该返回该QWidget的矩形区域。在实际中,这个rect设置为(0, 0, width, height)。
看这里的rect的引用,其实就是要对这个rect进行赋值,剩下的就交给Cef自己去做了。
第二个函数:
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width,
int height) = 0;
这个就比较关键了
它就是将获取的每一帧图片的数据存放在buffer指针指向内存中,width和height是这张图片的宽和高。
这个type,根据源码其实就是
typedef enum {
PET_VIEW = 0,
PET_POPUP,
} cef_paint_element_type_t;
这个枚举,这个可以先不用去管它,后面再深入了解它就行,知道有这么个参数就行。
第三步:
将第二步中OnPaint中获取的图像数据,贴到QWidget所在的矩形位置上。
通过事件,将刚刚获取的图像,以QImage对象的方式,发送给窗口,在paintEvent中将这个QImage贴到界面上(调用QPainter的drawImage)
第四步:
在窗口的resizeEvent事件中调用
调用CefBrowserHost的WasResized()方法,这样窗口大小变化的时候,离屏渲染出来的图像大小也会变化,我们看到的就是“浏览器”随着窗口的尺寸变化而变化。
以上就是我自己摸索出来的最简单的离屏渲染的几个步骤,接下来的几篇博客,我会逐步添加一些响应事件,让离屏渲染的功能更加完善。万丈高楼平地起,我们一步步来。
我们从代码开始:
main.cpp中
#include "cefosrwidget.h"
#include "simple_app.h"
#include "simple_handler.h"
#include <QApplication>
void QCefInitSettings(CefSettings & settings)
{
//std::string cache_path = AppGetWorkingDirectory().toStdString() + "/.cache";//缓存地址
// CefString(&settings.cache_path) = CefString(cache_path);
settings.multi_threaded_message_loop = true;//多线程消息循环
settings.log_severity = LOGSEVERITY_DISABLE;//日志
settings.windowless_rendering_enabled = true;
settings.no_sandbox = false;//沙盒
}
int QCefInit(int& argc, char** argv)
{
HINSTANCE hInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
CefMainArgs mainArgs(hInstance);
CefRefPtr<SimpleApp> app(new SimpleApp); //CefApp实现,用于处理进程相关的回调。
int exit_code = CefExecuteProcess(mainArgs, app.get(), nullptr);
if (exit_code >= 0) {
return exit_code;
}
CefSettings settings;
QCefInitSettings(settings);
CefInitialize(mainArgs, settings, app, nullptr);
return -1;
}
void CefQuit()
{
CefShutdown();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
int result = QCefInit(argc, argv);
if (result >= 0) {
return result;
}
CefOSRWidget widget;
widget.show();
a.exec();
CefQuit();
return 0;
}
simple_app.h
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
#include "include/cef_app.h"
// Implement application-level callbacks for the browser process.
class SimpleApp : public CefApp, public CefBrowserProcessHandler {
public:
SimpleApp();
// CefApp methods:
virtual CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler()
OVERRIDE {
return this;
}
// CefBrowserProcessHandler methods:
virtual void OnContextInitialized() OVERRIDE;
private:
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(SimpleApp);
};
#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_APP_H_
simple_app.cc
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "simple_app.h"
#include <string>
#include "include/cef_browser.h"
#include "include/cef_command_line.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_helpers.h"
#include "simple_handler.h"
namespace {
// When using the Views framework this object provides the delegate
// implementation for the CefWindow that hosts the Views-based browser.
class SimpleWindowDelegate : public CefWindowDelegate {
public:
explicit SimpleWindowDelegate(CefRefPtr<CefBrowserView> browser_view)
: browser_view_(browser_view) {}
void OnWindowCreated(CefRefPtr<CefWindow> window) OVERRIDE {
// Add the browser view and show the window.
window->AddChildView(browser_view_);
window->Show();
// Give keyboard focus to the browser view.
browser_view_->RequestFocus();
}
void OnWindowDestroyed(CefRefPtr<CefWindow> window) OVERRIDE {
browser_view_ = NULL;
}
bool CanClose(CefRefPtr<CefWindow> window) OVERRIDE {
// Allow the window to close if the browser says it's OK.
CefRefPtr<CefBrowser> browser = browser_view_->GetBrowser();
if (browser)
return browser->GetHost()->TryCloseBrowser();
return true;
}
CefSize GetPreferredSize(CefRefPtr<CefView> view) OVERRIDE {
return CefSize(800, 600);
}
private:
CefRefPtr<CefBrowserView> browser_view_;
IMPLEMENT_REFCOUNTING(SimpleWindowDelegate);
DISALLOW_COPY_AND_ASSIGN(SimpleWindowDelegate);
};
} // namespace
SimpleApp::SimpleApp() {}
void SimpleApp::OnContextInitialized() {
CEF_REQUIRE_UI_THREAD();
CefRefPtr<CefCommandLine> command_line =
CefCommandLine::GetGlobalCommandLine();
//// const bool use_transparent_painting =
//// use_windowless_rendering_ &&
// command_line_->HasSwitch(switches::kTransparentPaintingEnabled);
#if defined(OS_WIN) || defined(OS_LINUX)
// Create the browser using the Views framework if "--use-views" is specified
// via the command-line. Otherwise, create the browser using the native
// platform framework. The Views framework is currently only supported on
// Windows and Linux.
const bool use_views = command_line->HasSwitch("use-views");
#else
const bool use_views = false;
#endif
}
这些和前面的例子都一样,接下来就有点不同了:
simple_handler.h
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#ifndef CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
#define CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
#include "include/cef_client.h"
#include "include/base/cef_lock.h"
#include <list>
#include <QImage>
#include <QPainter>
#include <WinUser.h>
#include <QDebug>
#include <QObject>
class SimpleHandler : public CefClient,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefFocusHandler,
public CefDisplayHandler,
public CefRenderHandler //新加的
{
public:
explicit SimpleHandler(bool use_views);
~SimpleHandler() OVERRIDE;
void setWinHandle(HWND hwnd);
void setReceiver(QObject *receiver);
// Provide access to the single global instance of this object.
static SimpleHandler* GetInstance();
// CefClient methods:
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE { return this; }
virtual CefRefPtr<CefFocusHandler> GetFocusHandler() OVERRIDE { return this; }
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE { return this; }
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE { return this; }
virtual CefRefPtr<CefRenderHandler> GetRenderHandler() OVERRIDE { return this; } //新加的
// CefLifeSpanHandler methods:
virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE;
virtual bool DoClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE;
// CefLoadHandler methods:
virtual void OnLoadError(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
ErrorCode errorCode,
const CefString& errorText,
const CefString& failedUrl) OVERRIDE;
// CefFocusHandler methods
// virtual bool OnSetFocus(CefRefPtr<CefBrowser> browser, FocusSource source) OVERRIDE;
// Request that all existing browser windows close.
void CloseAllBrowsers(bool force_close);
bool IsClosing() const { return is_closing_; }
std::list<CefRefPtr<CefBrowser> > getCefBrowerList();
//CefRenderHandler methods
virtual void GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect) OVERRIDE;
virtual void OnPaint(CefRefPtr<CefBrowser> browser,
PaintElementType type,
const RectList& dirtyRects,
const void* buffer,
int width,
int height) OVERRIDE;
private:
// True if the application is using the Views framework.
const bool use_views_;
// List of existing browser windows. Only accessed on the CEF UI thread.
typedef std::list<CefRefPtr<CefBrowser>> BrowserList;
BrowserList browser_list_;
bool is_closing_;
// True if mouse cursor change is disabled.
bool m_bMouseCursorChangeDisabled;
HWND m_hwnd;
QObject *m_receiver;
// Include the default reference counting implementation.
IMPLEMENT_REFCOUNTING(SimpleHandler);
};
#endif // CEF_TESTS_CEFSIMPLE_SIMPLE_HANDLER_H_
simple_handler.cc
// Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "simple_handler.h"
#include <sstream>
#include <string>
#include <QDebug>
#include <QDateTime>
#include <QBuffer>
#include <QPixmap>
#include <QtWin>
#include <QCoreApplication>
#include "include/base/cef_bind.h"
#include "include/cef_app.h"
#include "include/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
#include "events.h"
namespace {
SimpleHandler* g_instance = NULL;
} // namespace
SimpleHandler::SimpleHandler(bool use_views)
: use_views_(use_views), is_closing_(false) {
DCHECK(!g_instance);
g_instance = this;
m_bMouseCursorChangeDisabled = false;
m_receiver = nullptr;
}
SimpleHandler::~SimpleHandler() {
g_instance = nullptr;
}
void SimpleHandler::setWinHandle(HWND hwnd)
{
m_hwnd = hwnd;
}
void SimpleHandler::setReceiver(QObject *receiver)
{
m_receiver = receiver;
}
// static
SimpleHandler* SimpleHandler::GetInstance() {
return g_instance;
}
void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD()
if (m_bMouseCursorChangeDisabled)
browser->GetHost()->SetMouseCursorChangeDisabled(true);
else
browser->GetHost()->SetMouseCursorChangeDisabled(false);
// Add to the list of existing browsers.
browser_list_.push_back(browser);
}
bool SimpleHandler::DoClose(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD()
// Closing the main window requires special handling. See the DoClose()
// documentation in the CEF header for a detailed destription of this
// process.
if (browser_list_.size() == 1) {
// Set a flag to indicate that the window close should be allowed.
is_closing_ = true;
}
// Allow the close. For windowed browsers this will result in the OS close
// event being sent.
return false;
}
void SimpleHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD()
// Remove from the list of existing browsers.
BrowserList::iterator bit = browser_list_.begin();
for (; bit != browser_list_.end(); ++bit) {
if ((*bit)->IsSame(browser)) {
browser_list_.erase(bit);
break;
}
}
if (browser_list_.empty()) {
// All browser windows have closed. Quit the application message loop.
CefQuitMessageLoop();
}
}
void SimpleHandler::OnLoadError(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
ErrorCode errorCode,
const CefString& errorText,
const CefString& failedUrl) {
CEF_REQUIRE_UI_THREAD()
qDebug() << "errorCode: " << errorCode;
// Don't display an error for downloaded files.
if (errorCode == ERR_ABORTED)
return;
// Display a load error message.
std::stringstream ss;
ss << "<html><body bgcolor=\"white\">"
"<h2>Failed to load URL "
<< std::string(failedUrl) << " with error " << std::string(errorText)
<< " (" << errorCode << ").</h2></body></html>";
frame->LoadString(ss.str(), failedUrl);
}
void SimpleHandler::CloseAllBrowsers(bool force_close) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute on the UI thread.
CefPostTask(TID_UI, base::Bind(&SimpleHandler::CloseAllBrowsers, this,
force_close));
return;
}
if (browser_list_.empty())
return;
BrowserList::const_iterator it = browser_list_.begin();
for (; it != browser_list_.end(); ++it)
(*it)->GetHost()->CloseBrowser(force_close);
}
std::list<CefRefPtr<CefBrowser> > SimpleHandler::getCefBrowerList()
{
return browser_list_;
}
void SimpleHandler::GetViewRect(CefRefPtr<CefBrowser> browser, CefRect &rect)
{
RECT clientRect;
if (!::GetClientRect(m_hwnd, &clientRect))
return;
rect.x = rect.y = 0;
rect.width = clientRect.right;
rect.height = clientRect.bottom;
return;
}
void SimpleHandler::OnPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList &dirtyRects,
const void *buffer,
int width,
int height)
{
HBITMAP bitmap= CreateBitmap(width,height,1,32,buffer);
QImage image = QtWin::imageFromHBITMAP(bitmap);
if (image.isNull())
{
qDebug() << "image is null";
return;
}
//以下为测试代码,将图片写到文件中去
//QString fileName = QString("D:/1/%1.png").arg(QDateTime::currentMSecsSinceEpoch());
//image.save(fileName, "PNG");
UpdateEvent *updateEvent = new UpdateEvent(image);
QCoreApplication::postEvent(m_receiver, updateEvent);
}
自定义事件,需要了解postEvent是在异步的,可以跨线程使用,如果不清楚,可以查阅相应资料
events.h
#ifndef EVENTS_H
#define EVENTS_H
#include <QEvent>
#include <QImage>
class UpdateEvent : public QEvent
{
public:
const static Type eventType = static_cast<Type>(QEvent::User+1);
explicit UpdateEvent(const QImage &image);
QImage m_image;
};
#endif // EVENTS_H
events.cpp
#include "events.h"
UpdateEvent::UpdateEvent(const QImage &image) :QEvent(eventType)
{
m_image = image;
}
cefosrwidget.h
#ifndef CEFOSRWIDGET_H
#define CEFOSRWIDGET_H
#include "simple_handler.h"
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class CefOSRWidget; }
QT_END_NAMESPACE
class CefOSRWidget : public QWidget
{
Q_OBJECT
public:
CefOSRWidget(QWidget *parent = nullptr);
~CefOSRWidget() override;
protected:
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override;
bool event(QEvent *event) override;
CefRefPtr<CefBrowser> getBrowser();
private:
Ui::CefOSRWidget *ui;
CefRefPtr<SimpleHandler> m_browserHander;
QImage m_image;
};
#endif // CEFOSRWIDGET_H
cefosrwidget.cpp
#include "cefosrwidget.h"
#include "ui_cefosrwidget.h"
#include "events.h"
#include <QMessageBox>
#include <QPainter>
#include <QMouseEvent>
#include <QDebug>
CefOSRWidget::CefOSRWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::CefOSRWidget)
{
ui->setupUi(this);
//Cef离屏渲染的话,设置了WA_TranslucentBackground也没有渲染问题
// setAttribute(Qt::WA_TranslucentBackground);
// setWindowFlags(Qt::FramelessWindowHint);
HWND wnd = (HWND)this->winId();
QString indexUrl = "www.baidu.com";
//这里可以换成本地的网,加载本地网页文件,格式为:file://绝对路径中的xx.html
//例如"file://" + QCoreApplication::applicationDirPath() + "/index.html"
CefWindowInfo cefWndInfo;
cefWndInfo.SetAsWindowless(wnd);
CefBrowserSettings cefBrowSetting;
// cefBrowSetting.background_color = 180;
cefBrowSetting.windowless_frame_rate = 60; //设置帧率,默认值是30
m_browserHander = CefRefPtr<SimpleHandler>(new SimpleHandler(false));
m_browserHander->setWinHandle(wnd);
m_browserHander->setReceiver(this);
//注意这里是异步创建
bool isCreated = CefBrowserHost::CreateBrowser(cefWndInfo, m_browserHander, CefString(indexUrl.toStdWString()), cefBrowSetting, nullptr, nullptr);
if (!isCreated)
{
QMessageBox::information(nullptr, "warning", "brower create failed!");
}
}
void CefOSRWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
CefRefPtr<CefBrowser> pBrower = getBrowser();
if (pBrower)
{
pBrower->GetHost()->WasResized();
pBrower->GetHost()->SetMouseCursorChangeDisabled(false);
}
}
void CefOSRWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QPainter painter(this);
QRect rect = this->rect();
// painter.setOpacity(0.5); //这里可以改变浏览器整体的透明度,比如这里设置为0.5
painter.drawImage(QRect(rect.left(), rect.top(), rect.width(), rect.height()), m_image, m_image.rect());
}
bool CefOSRWidget::event(QEvent *event)
{
if (event->type() == UpdateEvent::eventType)
{
UpdateEvent *updateEvent = dynamic_cast<UpdateEvent*>(event);
m_image = updateEvent->m_image;
this->update();
return true;
}
return QWidget::event(event);
}
CefRefPtr<CefBrowser> CefOSRWidget::getBrowser()
{
if (!m_browserHander.get())
{
return nullptr;
}
std::list<CefRefPtr<CefBrowser> > cefBrowerList = m_browserHander->getCefBrowerList();
if (cefBrowerList.size() == 0)
{
qDebug() << "cefBrowerList.size() == 0"; //浏览器是异步创建的,OnAfterCreated是在创建成功后调用的
return nullptr;
}
return cefBrowerList.front();
}
CefOSRWidget::~CefOSRWidget()
{
delete ui;
}

注意点:
在pro文件中,需要添加
LIBS += Gdi32.lib
要点讲解:
(1)离屏渲染需要继承CefRenderHandler,并且实现GetViewRect和OnPaint
(2)在OnPaint中
void SimpleHandler::OnPaint(CefRefPtr<CefBrowser> browser,
CefRenderHandler::PaintElementType type,
const CefRenderHandler::RectList &dirtyRects,
const void *buffer,
int width,
int height)
{
HBITMAP bitmap= CreateBitmap(width,height,1,32,buffer);
QImage image = QtWin::imageFromHBITMAP(bitmap);
if (image.isNull())
{
qDebug() << "image is null";
return;
}
//以下为测试代码,将图片写到文件中去
//QString fileName = QString("D:/1/%1.png").arg(QDateTime::currentMSecsSinceEpoch());
//image.save(fileName, "PNG");
UpdateEvent *updateEvent = new UpdateEvent(image);
QCoreApplication::postEvent(m_receiver, updateEvent);
}
使用了windows平台的API,将图形数据转成了HBITMAP格式图片,需要包含头文件
#include <QtWin>
以及在pro文件中添加
LIBS += Gdi32.lib
刚开始的时候,为了测试,将获取的图片,写到本地磁盘上,然后通过就可以知道是否获取到离屏的图片
//以下为测试代码,将图片写到文件中去
//QString fileName = QString("D:/1/%1.png").arg(QDateTime::currentMSecsSinceEpoch());
//image.save(fileName, "PNG");
(3)通过Qt的postEvent发送异步事件,去通知Qt窗口更新,将获取的QImage复制一份,放到自定义事件中。
UpdateEvent *updateEvent = new UpdateEvent(image);
QCoreApplication::postEvent(m_receiver, updateEvent);
为了可以指定接收者,需要添加
void setReceiver(QObject *receiver);
将Qt窗口的指针传递进来, 将离屏渲染得到的图片一张张发送给receiver,所以这里要指定接受者
(4)与真窗口不同的CefWindowInfo 设置:
HWND wnd = (HWND)this->winId();
QString indexUrl = "www.baidu.com";
//这里可以换成本地的网,加载本地网页文件,格式为:file://绝对路径中的xx.html
//例如"file://" + QCoreApplication::applicationDirPath() + "/index.html"
CefWindowInfo cefWndInfo;
cefWndInfo.SetAsWindowless(wnd);
CefBrowserSettings cefBrowSetting;
// cefBrowSetting.background_color = 180;
cefBrowSetting.windowless_frame_rate = 60; //设置帧率,默认值是30
(5)
重写event事件,根据自定义的更新事件,在paintEvent中进行重绘
protected:
bool event(QEvent *event) override;
bool CefOSRWidget::event(QEvent *event)
{
if (event->type() == UpdateEvent::eventType)
{
UpdateEvent *updateEvent = dynamic_cast<UpdateEvent*>(event);
m_image = updateEvent->m_image;
this->update();
return true;
}
return QWidget::event(event);
}
void CefOSRWidget::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
QPainter painter(this);
QRect rect = this->rect();
// painter.setOpacity(0.5); //这里可以改变浏览器整体的透明度,比如这里设置为0.5
painter.drawImage(QRect(rect.left(), rect.top(), rect.width(), rect.height()), m_image, m_image.rect());
}
离屏渲染,可以解决了Qt窗口中setAttribute(Qt::WA_TranslucentBackground);
背景透明时的显示问题。

试试将窗口设置为无边框,背景透明窗口。
本工程运行的是release版,代码放在百度云上
链接:https://pan.baidu.com/s/1XNstavzVVkTL2yq0Ee3iVg
提取码:hr13
下面是去掉了cef运行需要的资源文件(如果你看过我之前的教程,就可以下载下面的,体积更小)
链接:https://pan.baidu.com/s/1q-BxygVWCwuEWLfdpqzwKg
提取码:zfdj
接下来需要解决的问题:
(1)鼠标的点击事件
(2)滚轮事件
(3)鼠标hoved到链接上,鼠标形状的变化
(4)键盘输入
(5)输入框的右键弹出层
(这些问题会在后续说明如何处理。。。)
3382

被折叠的 条评论
为什么被折叠?



