基于CEF内核的简单浏览器实现(***)
来源:互联网 发布:电脑3d桌面软件 编辑:程序博客网 时间:2024/05/16 11:51
原文地址:http://blog.csdn.net/lixiang987654321/article/details/52154857
看本人该文章之前,首先必须先了解libcef的下载、编译等过程以及如何在MFC中使用CEF浏览器内核,如果不熟悉的伙伴们,请先看本人的前两篇文章,有了对应的库之后才能进行实现。
前一篇文章中介绍了如何在MFC中加载使用CEF内核,这是基础,我也在文章中提供了相应的Demon,但是对应的Demon功能不全,仅仅是将CEF内核加载进去并且使用了默认的URL(百度),而且我给出的Demon有个小问题就是对应的浏览器窗口嵌入到MFC的时候位置不对,与上面的工具栏差了四五十个像素,这里我纠正一下,原因是将CEF窗口设置为子窗口的时候,应该将对应的PICTURE控件的位置转换成相对于主对话框中的相对位置,也就是要将屏幕坐标转换成相对于主对话框的坐标(子窗口坐标),由于缺少改转换步骤导致了上面的问题,这篇文章提供的Demon已经解决了这个bug。当然本文提供的简单浏览器的功能有如下:
(1)主浏览器浏览的时候加载对应网页的URL显示到我们主窗口的CEdit控件中;
(2)实现浏览器的回退与前进浏览功能,并且前进或回退的网页URL也能及时显示;
(3)在浏览了多个网页之后,对应的回退和前进按钮要根据用户浏览顺序控制其能否回退或前进;
(4)主窗口最大化对应的主浏览器也能最大化;
(5)浏览网页标题能显示到我们窗口的标题中;
实现步骤如下(必须先看完我前一篇文章如何在MFC加载libcef一文章,这里我直接步入主题):
(1)网页标题的显示
在加载文档的时候,我们的事件处理器实现的CefDisplayHandler的接口,改接口中的有一个方法:
virtual void OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE;
改方法就是在某浏览器(一个网页一个浏览器窗口)标题发生变化的时候出发的回调,也就是我们在这里能够通过浏览器的标题变化事件,将加载的网页的标题显示到对应的浏览器的窗口中,由于主浏览器窗口被嵌入到我们的主对话框中,所以主对话框的标题要设置为主浏览器的标题,其他以链接形式打开的弹出式窗口则设置为自己浏览器的标题;每一个浏览器对应一个Frame窗口,也就是Browser->GetMainFrame获取对应的主窗口,主窗口中IsMain方法标志了这个是根主窗口还是由根浏览器产生的子浏览器窗口;
代码如下:
void CCefBrowserEventHandler::OnTitleChange(CefRefPtr<CefBrowser> browser, const CefString& title) OVERRIDE{CefWindowHandle hwnd = browser->GetHost()->GetWindowHandle();// 如果为被嵌入到主对话框的主浏览器窗口则更改我们对话框标题if (GetParent(hwnd) == AfxGetApp()->m_pMainWnd->GetSafeHwnd()) {AfxGetApp()->m_pMainWnd->SetWindowText(std::wstring(title).c_str());}// 否则有内核创建(链接形式打开)的窗口标题设置为自己的窗口标题else{::SetWindowText(hwnd, std::wstring(title).c_str());}}
(2)主浏览器浏览的时候加载对应网页的URL显示到我们主窗口的CEdit控件中;
在浏览器载入某网页的时候会发生浏览器地址变化消息,我们可以捕获CefDisplayHandler处理器中的方法
void OnAddressChange(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString& url) ;
由于我们需要检测主浏览器窗口(主对话框的子窗口)的URL变化,所以主浏览器URL变化的时候,我们只需要将主浏览器的URL显示到对话框即可。主浏览器判断是否是主浏览器窗口通过其窗口的IsMain方法判断;
void CCefBrowserEventHandler::OnAddressChange(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,const CefString& url) OVERRIDE{if (frame->IsMain()){AfxGetApp()->m_pMainWnd->SendMessage(WM_URL_CHANGED, (WPARAM)(LPCTSTR)url.c_str(), 0);}}
(3)在浏览了多个网页之后,对应的回退和前进按钮要根据用户浏览顺序控制其能否回退或前进;浏览器加载页面的时候是一个过程,这个过程中是一个变化的过程,所以是一个状态变化过程,过程变化事件我们可以通过加载处理器CefLoadHandler的
void OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,boolcanGoForward)
回调事件捕获,改事件参数中表明了当前访问页是否可以回退或者先前翻页;通过后两个参数控制按钮的可用性
void CCefBrowserEventHandler::OnLoadingStateChange(CefRefPtr<CefBrowser> browser,bool isLoading,bool canGoBack,bool canGoForward) OVERRIDE{if (browser->GetMainFrame()->IsMain()){AfxGetApp()->m_pMainWnd->SendMessage(WM_LOAD_CHANGED, canGoBack, canGoForward);}}(4)实现浏览器的回退与前进浏览功能,并且前进或回退的网页URL也能及时显示;浏览器中CBrowser控制浏览的页面的基本操作,包括回退、前进等,Frame里则主要控制窗口中的事件,包括菜单、打印等等事件,所以知道之后(这里我要说两句,我知道这些就是查看了对应接口的方法,见名知意,不知道的看英文就能明白,包括对应的处理器事件接口,我们可以读一读就能明白里面接口的含义)我们只需要调用对应的浏览器的方法GoBack或GoForword即可达到回退和前进功能;
void CCef_DemonDlg::OnBnClickedButtonBack(){// TODO: 在此添加控件通知处理程序代码if (CCefBrowserEventHandler::GetInstance()->GetMainBrowser()){CCefBrowserEventHandler::GetInstance()->GetMainBrowser()->GoBack();}}void CCef_DemonDlg::OnBnClickedButtonNext(){// TODO: 在此添加控件通知处理程序代码if (CCefBrowserEventHandler::GetInstance()->GetMainBrowser()){CCefBrowserEventHandler::GetInstance()->GetMainBrowser()->GoForward();}}
其中,我们这里的事件处理器中提供了获取全局实例的方法GetInstance以及获取主窗口的方法,拿到对应主浏览器之后直接调用GoBack和GoForward即可。
(5)主窗口最大化对应的主浏览器也能最大化;这个就很简单了,捕获Dialog的Onsize消息,处理对应位置即可;
代码简单如下:
void CCef_DemonDlg::OnSize(UINT nType, int cx, int cy){CDialog::OnSize(nType, cx, cy);OnCtrlSize();}void CCef_DemonDlg::OnCtrlSize(){int nHeadHeight = 27;int nBtnWidth = 55;CRect rtClient;GetClientRect(&rtClient);CRect rtBtn;if (::IsWindow(GetDlgItem(IDC_BUTTON_BACK)->GetSafeHwnd())){rtBtn = rtClient;rtBtn.left += 1;rtBtn.top += 1;rtBtn.right = rtBtn.left + nBtnWidth;rtBtn.bottom = rtBtn.top + nHeadHeight;GetDlgItem(IDC_BUTTON_BACK)->MoveWindow(&rtBtn);}if (::IsWindow(GetDlgItem(IDC_BUTTON_NEXT)->GetSafeHwnd())){rtBtn.left = rtBtn.right + 1;rtBtn.right = rtBtn.left + nBtnWidth;GetDlgItem(IDC_BUTTON_NEXT)->MoveWindow(&rtBtn);}int nUrlLeft = rtBtn.right + 1;if (::IsWindow(GetDlgItem(IDC_BUTTON_GO)->GetSafeHwnd())){rtBtn = rtClient;rtBtn.top += 1;rtBtn.right -= 1;rtBtn.left = rtBtn.right - nBtnWidth;rtBtn.bottom = rtBtn.top + nHeadHeight;GetDlgItem(IDC_BUTTON_GO)->MoveWindow(&rtBtn);}int nUrlRight = rtBtn.left - 1;CRect rtEdit;if (::IsWindow(GetDlgItem(IDC_EDIT_URL)->GetSafeHwnd())){rtEdit = rtClient;rtEdit.top += 1;rtEdit.bottom = rtEdit.top + nHeadHeight;rtEdit.left = nUrlLeft;rtEdit.right = nUrlRight;GetDlgItem(IDC_EDIT_URL)->MoveWindow(&rtEdit);}CRect rtBody;if (::IsWindow(GetDlgItem(IDC_STATIC_BODY)->GetSafeHwnd())){rtBody = rtClient;rtBody.left += 1;rtBody.right -= 1;rtBody.top = rtEdit.bottom + 1;GetDlgItem(IDC_STATIC_BODY)->MoveWindow(&rtBody);::MoveWindow(CCefBrowserEventHandler::GetInstance()->GetMainBrowser()->GetHost()->GetWindowHandle(),rtBody.left, rtBody.top, rtBody.Width(), rtBody.Height(), TRUE);}}
好了,看了对应的几个问题之后就是看看实现效果了:
(1)启动默认打开百度
(2)访问CSDN
(3)回退到百度页面
(4)前进到CSDN页面
(5)打开链接
对应Demon下载链接: http://download.csdn.net/detail/lixiang987654321/9598429
- 基于CEF内核的简单浏览器实现(***)
- 基于Cef的简易浏览器开发(CefSharp)
- 基于Cef的简易浏览器开发(CefSharp)
- 基于内嵌浏览器内核(如XULRunner、CEF)来开发桌面软件
- duilib + cef简单浏览器的demo
- MFC对话框应用程序中谷歌CEF浏览器内核的使用
- MFC对话框应用程序中谷歌CEF浏览器内核的使用
- MFC对话框应用程序中谷歌CEF浏览器内核的使用
- 基于OpenCV的视频图像组态 (9):CEF浏览器初步
- 基于Cef内核的多店铺登录器(含源码)
- chrominum cef 简单实现
- duilib + cef简单浏览器的demo2--c++和js交互
- Windows上使用CEF嵌入基于chrome内核浏览器小例
- 在mfc中使用cef实现webkit的浏览器(一)-准备工作
- 在mfc中使用cef实现webkit的浏览器(二)-修改项目属性
- 在 .NET 中开发基于 Chrome 内核的浏览器-创建一个简单浏览器
- 基于OpenCV的视频图像组态 (10): CEF浏览器与图形软件互嵌
- 基于OpenCV的视频图像组态 (11): CEF浏览器与C++通信
- 嵌入式Qt-4.8.6显示中文并且改变字体大小和应用自己制作的字体库
- c语言趣味编程100例——迭代循环:
- 使用进程来打开应用程序
- running doppia on Jetson TX1
- 阶乘因式分解(一)
- 基于CEF内核的简单浏览器实现(***)
- 基于用户的协同过滤推荐—实现电影推荐
- memcpy原码引发的内存拷贝注意事项
- c语言中6大排序算法实现和解析
- jquery 针对html标签一些常用方法(select、radio、checkbox)
- golang:An operation on a socket could not be performed because the system lacked sufficient buffer s
- 学习Qt的QML的Canvas(一) ---(参考书籍 《Qt Quick 核心编程-安晓辉》)
- 数据库查看EZ状态的脚本
- 【10】Hibernate的一对多的映射