qt有自带的浏览器,好像也是谷歌浏览器的内核,但是没有用过不知道性能怎么样.cef需要用Cmake生成VS工程文件,在VS中先编译libcef_dll_wrapper,大概是生成cef的适配器,然后生成cefsimple,到这个工程下的Debug目录找到cefsimple.exe,运行成功,我的另外一篇例子有详细的过程.
cef集成到qt
下载msvc版本的qt,这个版本的可以使用vs的编译器,比如
qt-opensource-windows-x86-msvc2015_64-5.7.1.exe
下载地址
http://download.qt.io/archive/qt/5.7/5.7.1/
qt另外有MinGW版本的,这个可能不能集成cef
接下家重新编译libcef_dll_wrapper,更改运行库的线程方式.
项目——属性——配置属性——C/C++——代码生成:他有/MT,/MTd,/Md,/MDd四个选项,你必须让所有使用的库都使用相同的配置,否则就会有相应的提示,甚至可能会出现无法解析的函数。有时我们使用的库不是自己可以控制的,那么就只能把工程属性设置成河你使用的库相同的选项。
参考 https://blog.csdn.net/pgmsoul/article/details/4203941
把这个选项选改为 MD ,然后重新编译libcef_dll_wrapper. 往qt移植需要改一下,在vs里不用了
参考 https://blog.csdn.net/fanhenghui/article/details/79781130
然后新建Qt工程,或者导入我的qt工程.
https://pan.baidu.com/s/1ZPjHIH0Mv29jSJmcMTNv4Q
其实就是有几个文件.
在工程目录下新建cef文件夹,在新建include和lib文件夹.把cef编译前的include内容复制到cef/include文件夹内.
把libcef_dll_wrapper用MD方式编译后的libcef_dll_wrapper.dll和cef源码/Debug/libcef.lib,两个文件放在cef/lib下
我把他贴出来
JDzBrowser.pro
#-------------------------------------------------
#
# Project created by QtCreator 2018-11-13T09:18:32
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = JDzBrowser
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += main.cpp\
simple_app.cc \
simple_handler.cc \
widget.cpp
HEADERS += simple_app.h \
simple_handler.h \
widget.h
FORMS += widget.ui
INCLUDEPATH+=$$PWD/cef/
LIBS += shell32.lib \
$$PWD/cef/lib/libcef.lib \
$$PWD/cef/lib/libcef_dll_wrapper.lib \
kernel32.lib \
user32.lib \
ole32.lib \
oleaut32.lib \
gdi32.lib
RC_FILE += icon.rc
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;
void OnBeforeCommandLineProcessing(const CefString & process_type, CefRefPtr<CefCommandLine> command_line);
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 "simple_handler.h"
#include "include/cef_browser.h"
#include "include/cef_command_line.h"
#include "include/wrapper/cef_helpers.h"
SimpleApp::SimpleApp() {
}
void SimpleApp::OnContextInitialized() {
CEF_REQUIRE_UI_THREAD();
}
void SimpleApp::OnBeforeCommandLineProcessing(const CefString & process_type, CefRefPtr<CefCommandLine> command_line)
{
//加载flash插件
command_line->AppendSwitchWithValue("--ppapi-flash-path", "ppflash/18_0_0_209/pepflashplayer32_18_0_0_209.dll");
//manifest.json中的version
command_line->AppendSwitchWithValue("--ppapi-flash-version", "18.0.0.209");
command_line->AppendSwitch("--disable-extensions");
}
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 <list>
// List of existing browser windows. Only accessed on the CEF UI thread.
typedef std::list<CefRefPtr<CefBrowser> > BrowserList;
class Widget;
class SimpleHandler : public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefLoadHandler {
public:
SimpleHandler(Widget* widget);
~SimpleHandler();
// Provide access to the single global instance of this object.
static SimpleHandler* GetInstance();
// CefClient methods:
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() OVERRIDE {
return this;
}
virtual CefRefPtr<CefLoadHandler> GetLoadHandler() 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;
// Request that all existing browser windows close.
void CloseAllBrowsers(bool force_close);
bool IsClosing() const { return is_closing_; }
BrowserList GetBrowserList(){return browser_list_;}
private:
BrowserList browser_list_;
Widget* widget;
bool is_closing_;
// 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 "include/base/cef_bind.h"
#include "include/cef_app.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.h"
#include "widget.h"
namespace {
SimpleHandler* g_instance = NULL;
} // namespace
SimpleHandler::SimpleHandler(Widget* w)
: is_closing_(false) {
DCHECK(!g_instance);
g_instance = this;
this->widget=w;
}
SimpleHandler::~SimpleHandler() {
g_instance = NULL;
}
// static
SimpleHandler* SimpleHandler::GetInstance() {
return g_instance;
}
void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
CEF_REQUIRE_UI_THREAD();
// Add to the list of existing browsers.
browser_list_.push_back(browser);
int nID = browser->GetIdentifier();
widget->browserId=nID;
}
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();
// 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);
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "simple_handler.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
int browserId;
private:
Ui::Widget *ui;
CefRefPtr<SimpleHandler> m_browserEvent;
CefRefPtr<CefBrowser> GetBrowserByID(int nWebBrowserID);
public slots:
void onUrl();
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDesktopWidget>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
HWND wnd = (HWND)ui->widget->winId();
CefWindowInfo cefWndInfo;
QString strUrl = "https://www.baidu.com";
//QString strUrl = "chrome://version";
RECT winRect;
QDesktopWidget* pDeskTop = QApplication::desktop();
QRect qtRect = pDeskTop->screenGeometry();
winRect.left = qtRect.left();
winRect.top = qtRect.top();
winRect.right = qtRect.right();
winRect.bottom = qtRect.bottom();
cefWndInfo.SetAsChild(wnd, winRect); //将cef界面嵌入qt界面中
CefBrowserSettings cefBrowSetting;
m_browserEvent = CefRefPtr<SimpleHandler>(new SimpleHandler(this));
bool browser = CefBrowserHost::CreateBrowser(cefWndInfo, m_browserEvent, strUrl.toStdString(), cefBrowSetting, NULL);
connect(ui->goButton, SIGNAL(clicked()), this, SLOT(onUrl()));
showMaximized();
}
Widget::~Widget()
{
delete ui;
}
CefRefPtr<CefBrowser> Widget::GetBrowserByID(int nWebBrowserID)
{
for (auto it = m_browserEvent->GetBrowserList().begin(); it != m_browserEvent->GetBrowserList().end(); it++)
{
if (nWebBrowserID == it->get()->GetIdentifier())
{
return it->get();
}
}
return nullptr;
}
void Widget::onUrl()
{
CefRefPtr<CefBrowser> pBrower = GetBrowserByID(browserId);
if (pBrower)
{
pBrower->GetMainFrame()->LoadURL(ui->lineEdit->text().toStdString());
}
}
main.cpp
#include "widget.h"
#include <QApplication>
#include "simple_app.h"
#include "simple_handler.h"
void QCefInitSettings(CefSettings & settings)
{
// qDebug()<<"QCefInitSettings";
//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.no_sandbox = true;//沙盒
}
int QCefInit(int& argc, char** argv)
{
// qDebug()<<"QCefInit";
HINSTANCE hInstance = static_cast<HINSTANCE>(GetModuleHandle(nullptr));
CefMainArgs mainArgs(hInstance);
//CefRefPtr<SimpleApp> app(new SimpleApp);
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);
//m_handler = new QCefClientHandler();
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;
}
Widget w;
w.show();
a.exec();
CefQuit();
return 0;
}
widget.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Widget</class>
<widget class="QWidget" name="Widget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>cef qt test</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="toolbar" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>40</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="lineEdit">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>40</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">font-size:15px;</string>
</property>
<property name="text">
<string>http://www.qq.com</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="goButton">
<property name="minimumSize">
<size>
<width>0</width>
<height>40</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>40</height>
</size>
</property>
<property name="text">
<string>访问</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true"/>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections/>
</ui>
然后在qt中构建项目
得到这样的构建目录.
其中的.exe就是我们的主程序
我们还需要将qt的运行时库,dll,复制到主程序目录.
在qt安装目录搜索这几个dll.
复制到主程序目录下.
在再cefsimple下,把除了cefsimple.exe,和后缀是exp,ilk,pdb,其他的文件都复制到主程序相同目录
运行JDzBrowser.exe
我的编译结果