CEF学习小记(二)-如何使浏览器窗口随对话框一起缩放

来源:互联网 发布:sql replace 编辑:程序博客网 时间:2024/06/06 18:20

转自:http://blog.csdn.net/yitucom123/article/details/52948507


通过上一篇文章,已经可以浏览网页了,但有一个问题,就是那最大化对话框后,网页的浏览区域并没有变,如何让浏览区域变化呢?

我参考了两篇文章,一篇是(http://blog.csdn.net/cyloser/article/details/49734559),另一篇是(http://www.heycode.com/a13696.html)。感谢这两篇文章的作者,没有这两篇文章,我估计还在纠结为会么CefSize::Set(…)函数为什么不能改变窗口大小呢!当然如果有人知道如何使用Set()函数,请不吝赐教。

解决方法

我们知道,窗口大小的改变通常会产生WM_SIZE消息。那么首先应该在对话框中添加OnSize函数。此外,要控制浏览器窗口,必须要获得其句柄或指针,如何获得呢?这就是本文主要讲解的内容。 
在(一)中搭建CEF用到了cefsimple示例中的五个文件,这五个文件可以实现最基本的功能。为了探究cefsimple如何完成窗口缩放的功能,我尝试在整个cefsimple中搜索WM_SIZE,然而并没有搜到。由于时间问题 ,我没有去分析cefsimple的源码,而是去cefclient项目的去找答案。在cefclient项目,很容易就在cefclient_win.cpp中搜到了,通过代码分析,将主要代码写在下方:

  if (!g_handler.get())        break;  CefRefPtr<CefBrowser> browser=g_handler->GetBrowser();  if (browser/*g_handler->GetBrowser()*/)   {        // Retrieve the window handle (parent window with off-screen rendering).        CefWindowHandle hwnd =g_handler->GetBrowser()->GetHost()->GetWindowHandle();        if (hwnd)         {            // Resize the window and address bar to match the new frame size.            RECT rect;            GetClientRect(hWnd, &rect);            rect.top += URLBAR_HEIGHT;            ......          }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

上面这段代码说明了什么呢?首先检查g_handler.get()是否为0,为0就直接退出了WM_SIZE的消息处理了。在为非0的情况下,获得浏览器的智能指针(CefRefPtr),并对其进行判断。在browser非零的情况下才能获得浏览窗口的句柄,然后根据客户的界面进行更改。 
可能你会问:g_handler是什么变量?对g_handler进行追踪,发现这是一个在cefclient.cpp中定义的全局变量,CefRefPtr g_handler;。所以在完全按照前一篇文章是不行的,应将app,handler的声明为全局变量,并分别在构造函数和OnInitDialog中进行初始化,模板分别为SimpleApp、SimpleHandler。然而就这样还是不能使用,因为g_handler并没有GetBrowser() 这样的成员函数,怎么办?还得回到cefclient项目中寻找答案。 
在client_handler.h和client_handler.cpp中找到了GetBrowser()的声明和定义。

.h // Lock used to protect members accessed on multiple threads. Make it mutable// so that it can be used from const methods.mutable base::Lock lock_;// The child browser window.CefRefPtr<CefBrowser> browser_;CefRefPtr<CefBrowser> GetBrowser() const;----------.cpp CefRefPtr<CefBrowser> ClientHandler::GetBrowser() const {  base::AutoLock lock_scope(lock_);  return browser_;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

得到了GetBrowser的声明和定义,问题又来了,lock_和browser_是什么鬼?然而就这么用到你的工程中还是不是的,否则就会出现如下错误提示: 
这里写图片描述 
通过对cefclient中lock_的类型base::Lock分析,发现这是在include/base/cef_lock.h中定义的,所以在handler.h中务必要加上#include “include/base/cef_lock.h”。请注意,不要不加思考地对代码进行复制!!,ClientApp,ClientHandler这些类名一定要改成自已项目中定义的。 
现在完成对OnSize()函数的编写,代码如下:

void CceftestDlg::OnSize(UINT nType, int cx, int cy){    CDialogEx::OnSize(nType, cx, cy);    if(g_handler!=NULL)    {        CefRefPtr<CefBrowser> browser=g_handler->GetBrowser();        if(browser)        {            CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();            ::MoveWindow(hwnd,0,0,cx,cy,TRUE);  //因为浏览器对于对话框是子窗口,所以浏览器的左上角坐标是相于父窗口的客户区的左上角而言的        }    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

编译一下,通过了。运行,发现居然还是老样子。怎么回事?!只好对OnSize进行断点调试,发现if(browser)的判断体始终没有执行。不信邪的我回到cefclient项目进行WM_SIZE处进行断点调试,发现browser_非0。于是我意识到我一定在SimpleHandler.cpp中漏掉了对browser_的一些操作。在cefclient项目的cef_handler.cpp中搜索对browser_的操作,找到了两处,分别是在OnAfterCreated和OnBeforeClose,一个是在创建之后,一个是在关闭之前,刚后形成互补,代码如下:

void ClientHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {    ......     if (!GetBrowser())   {    base::AutoLock lock_scope(lock_);    // We need to keep the main child window, but not popup windows    browser_ = browser;    browser_id_ = browser->GetIdentifier();  }   ......}void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {...... if (GetBrowserId() == browser->GetIdentifier()) {    {      base::AutoLock lock_scope(lock_);      // Free the browser pointer so that the browser can be destroyed      browser_ = NULL;    }    ......}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

由于只有一个浏览器窗口,所以关于窗口ID的操作就可以无视了。简化代码后如下:

void SimpleHandler::OnAfterCreated(CefRefPtr<CefBrowser> browser) {......    if (!GetBrowser())    {      base::AutoLock lock_scope(lock_);      // We need to keep the main child window, but not popup windows      browser_ = browser;    }    ......}void SimpleHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser) {......    base::AutoLock lock_scope(lock_);   //这一句包括下一句一定要有,否则就会在退出程序时报错,进程无法释放    // Free the browser pointer so that the browser can be destroyed    browser_ = NULL;......}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

好了,现在再对项目进行编译运行。效果如下。 
这里写图片描述

后记: 
我自己在处理对browser_的一些补全操作时,第一次只在OnAfterCreated中加了相关代码,没有意识到要在OnBeforeClosed中加,结果也成功达到了目的,但是会出现一个奇怪的问题,就是在退出时会报错。花了好长时间才明白browser_出现在OnAfterCreated和OnBeforeClosed中是有原因的,一个初始化,一个销毁,官方在注释中也说明了这一点。