windows下Qt中的第一个Cef3程序

上一篇我们编译了vs2017版本的Cef3,记得那一步的需要修改成/MD,编译出Debug版本和Release版本。
我们还是以cef_binary_75.0.1+gb5e74dd+chromium-75.0.3770.80_windows64.tar.bz2这个版本为准。(原因见上一篇博客)。

我们修改simple_app.cc中的url为"http://www.baidu.com",否则会发现打开cefsimple.exe时半天显示不了网页。(原链接为"http://www.google.com",不科学上网,半天出现不了。)
在这里插入图片描述
我们以编译的x64 Release版本为例:
在这里插入图片描述
在VS2017中,设置cefsimple为启动项目,或者在在build文件夹下,双击cefsimple.exe打开。
注意观察这个目录的文件结构。
在CMake的输出窗口可以看到:
在这里插入图片描述
我把它稍微排版了一下:

CEF Binary files:             
	chrome_elf.dll;
	d3dcompiler_47.dll;
	libcef.dll;
	libEGL.dll;
	libGLESv2.dll;
	natives_blob.bin;
	snapshot_blob.bin;
	v8_context_snapshot.bin;swiftshader

CEF Resource files:           
	cef.pak;
	cef_100_percent.pak;
	cef_200_percent.pak;
	cef_extensions.pak;
	devtools_resources.pak;
	icudtl.dat;
	locales

这些都是我们将来编译的exe同级目录中需要的文件,有CEF二进制文件和CEF资源文件。

运行效果:
在这里插入图片描述
我们现在将把这个例子在Qt中实现出来。
我们新建一个Qt Widgets Application工程,保留ui文件。
在这里插入图片描述
就是一个布局加一个QWidget,命令为contentWidget
新看看工程的目录结构
在这里插入图片描述
在这里插入图片描述
这个include文件夹就在这里插入图片描述
lib存放我们编译出来的Debug版本库和Release库
在这里插入图片描述
其实我们编译的时候
在这里插入图片描述
这个cef_sandbox.lib在我们这个demo中用不到。
在这里插入图片描述
在这里插入图片描述
cef.pri是我们建立的一个文本文件,内容:


INCLUDEPATH += $$PWD
INCLUDEPATH += $$PWD/include

win32:CONFIG(debug, debug|release) {
    LIBS += $$PWD/lib/debug/libcef.lib \
            $$PWD/lib/debug/libcef_dll_wrapper.lib \
            user32.lib
}
else:win32:CONFIG(release, debug|release) {
    LIBS += $$PWD/lib/release/libcef.lib \
            $$PWD/lib/release/libcef_dll_wrapper.lib \
            user32.lib
}

这样我们就可以Debug版本和Release版本分别链接不同的lib库。

把vs工程中的

simple_app.h
simple_app.cc
simple_handler.h
simple_handler.cc

都拷贝到Qt工程中
注意修改:
在这里插入图片描述
在这里插入图片描述
在simple_handler.h中添加getCefBrowerList函数
在这里插入图片描述
simple_handler.cpp中添加函数定义:

std::list<CefRefPtr<CefBrowser> > SimpleHandler::getCefBrowerList()
{
    return browser_list_;
}

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/views/cef_browser_view.h"
#include "include/views/cef_window.h"
#include "include/wrapper/cef_closure_task.h"
#include "include/wrapper/cef_helpers.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;
}

SimpleHandler::~SimpleHandler() {
  g_instance = NULL;
}

// static
SimpleHandler* SimpleHandler::GetInstance() {
  return g_instance;
}

void SimpleHandler::OnTitleChange(CefRefPtr<CefBrowser> browser,
                                  const CefString& title) {
  CEF_REQUIRE_UI_THREAD();

  if (use_views_) {
    // Set the title of the window using the Views framework.
    CefRefPtr<CefBrowserView> browser_view =
        CefBrowserView::GetForBrowser(browser);
    if (browser_view) {
      CefRefPtr<CefWindow> window = browser_view->GetWindow();
      if (window)
        window->SetTitle(title);
    }
  } else {
    // Set the title of the window using platform APIs.
    // PlatformTitleChange(browser, title);
  }
}

void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
  CEF_REQUIRE_UI_THREAD();

  // 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();

  // 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_;
}

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include "simple_handler.h"

#include <QWidget>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget() override;

protected:
    void resizeEvent(QResizeEvent *event) override;

private:
    Ui::Widget *ui;

    CefRefPtr<SimpleHandler> m_browserHander;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"

#include <WinUser.h>

#include <QDesktopWidget>
#include <QMessageBox>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    HWND wnd = (HWND)ui->contentWidget->winId();
    QString indexUrl = "www.baidu.com";

    RECT winRect;
    QRect messageRect(0, 0, 800, 600);

    winRect.left = messageRect.left();
    winRect.top = messageRect.top();
    winRect.right = messageRect.right();
    winRect.bottom = messageRect.bottom();

    CefWindowInfo cefWndInfo;
    cefWndInfo.SetAsChild(wnd, winRect);  //将cef界面嵌入qt界面中

    CefBrowserSettings cefBrowSetting;
    m_browserHander = CefRefPtr<SimpleHandler>(new SimpleHandler(false));
    bool browser = CefBrowserHost::CreateBrowser(cefWndInfo, m_browserHander, CefString(indexUrl.toStdWString()), cefBrowSetting, nullptr, nullptr);
    if (!browser)
    {
        QMessageBox::information(NULL, "warning", "brower create failed!");
    }
}

void Widget::resizeEvent(QResizeEvent *event)
{
    QWidget::resizeEvent(event);

    if (!m_browserHander.get())
    {
        return;
    }

    std::list<CefRefPtr<CefBrowser> > cefBrowerList = m_browserHander->getCefBrowerList();
    if (cefBrowerList.size() == 0)
    {
        qDebug() << "cefBrowerList.size() == 0"; //第一次resizeEvent的时候,这个为0。Qt中resizeEvent只有在窗口显示出来后,才能获取到正确的窗口尺寸值。
        return;
    }

    CefRefPtr<CefBrowser> pBrower = cefBrowerList.front();

    if (pBrower.get())
    {
        HWND hwnd_ = pBrower->GetHost()->GetWindowHandle();
        if (hwnd_)
        {
            QSize browserSize = ui->contentWidget->size();
            ::MoveWindow(hwnd_, 0, 0, browserSize.width(), browserSize.height(), TRUE);
        }
    }
}

Widget::~Widget()
{
    delete ui;
}

最重要的是
main.cpp

#include "widget.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.single_process = true;

    settings.no_sandbox = true;//沙盒
}

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;
    }

    Widget w;
    w.show();

    a.exec();
    CefQuit();

    return 0;
}

编译成功,运行不了。-_-||

需要将Cef需要的二进制文件和资源文件全部拷贝到Qt编译目录中(区分Debug和Release)
在这里插入图片描述
再运行:
在这里插入图片描述
我会将这个demo放上来,让大家下载。

链接:https://pan.baidu.com/s/1lo3SJxpJBBwH8cP3uU6oyg
提取码:5q4r

如果运行不起来,我无法一一解答,因为这里编译的的动态库版本的cef3,可能每个人的运行库不同,还有windows系统安装的一些库不同等都有差别,包括编译使用的windows SDK的版本也是不同的。需要自己手动编译cef3,自行摸索。

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值