编译Chrome开源代码是一件很恐怖的事情,代码庞大,还需要各种工具配合。在windows上快速开发chrome内核网页程序,Libcef是一个很好的选择。最近趁空闲时间,写了一个简单的浏览器,很多功能都没有完善,不知道以后还会不会继续写了,PC端确实是萎了。
在前面的几篇文章中大概介绍了下Libcef的使用,很多时候我们都会遇到各种问题,建议去看看它的接口函数声明,里面的注释写的非常清楚。
libCEF中C++与JavaScript的交互调
Windows上使用CEF嵌入基于chrome内核浏览器小例
程序运行截图
首先需要解决的是浏览器的Tab控件,扩展Duilib控件,每一个Tab控件就是一个容器里面存放着一系列Item,根据Item的个数和Tab的尺寸来计算每一个Item 节点的宽度。
对于单个节点Item控件,里面又有一个子Button控件,也就是关闭按钮。对于这个Item的消息进行处理,包括选中、双击、关闭,把这些消息都转发到父控件Tab中去处理。Tab控件同一管理这些控件的哪一个是选中状态。
然后是Libcef控件的创建,Tab中点击Add按钮后,需要创建网页控件并加载到当前窗口中去。整个父窗口在大小发生变化时,又要通知里面所有的Libcef子窗口随之变化。
然后就是关闭时,要让所有的Libcef子进程都能正常退出,就必须按照Libef文档说的那样,在退出时调用CefQuitMessageLoop()。
Duilib扩展Tab控件
#pragma once #include "ScrollTabUI.h" class CScrollOptionUI : public CContainerUI { public: CScrollOptionUI(void); ~CScrollOptionUI(void); void SetParent(CScrollTabUI* pTab) { m_pParent = pTab; } protected: virtual void Init(); virtual void PaintText(HDC hDC); virtual void SetPos(RECT rc); virtual void DoEvent(TEventUI& event); bool OnBtnClose(void* pParam); private: CButtonUI* m_pBtnExit; CScrollTabUI* m_pParent; };
#include "StdAfx.h" #include "ScrollOptionUI.h" #define BTN_CLOSE_WIDTH 14 #define BTN_CLOSE_HEIGHT 14 CScrollOptionUI::CScrollOptionUI(void) : m_pBtnExit(NULL) , m_pParent(NULL) { } CScrollOptionUI::~CScrollOptionUI(void) { } void CScrollOptionUI::Init() { m_pBtnExit = new CButtonUI; CDuiString strAttr; strAttr.Format(L"float=\"true\" pos=\"%d,%d,%d,%d\" normalimage=\"close_nor.png\" hotimage=\"close_hot.png\" pushedimage=\"close_push.png\"", m_cxyFixed.cx-BTN_CLOSE_WIDTH, 0, m_cxyFixed.cx, BTN_CLOSE_HEIGHT); m_pBtnExit->ApplyAttributeList(strAttr); Add(m_pBtnExit); m_pBtnExit->OnNotify += MakeDelegate(this, &CScrollOptionUI::OnBtnClose); } void CScrollOptionUI::PaintText( HDC hDC ) { RECT rc = m_rcItem; rc.left += 4; rc.right-= 10; CRenderEngine::DrawText(hDC, m_pManager, rc, m_sText, 0xFF666666, 0, DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS); } void CScrollOptionUI::SetPos( RECT rc ) { CContainerUI::SetPos(rc); RECT rcExit = {rc.right-BTN_CLOSE_WIDTH-1, rc.top+1, rc.right-1, rc.top+BTN_CLOSE_HEIGHT+1}; m_pBtnExit->SetPos(rcExit); } void CScrollOptionUI::DoEvent( TEventUI& event ) { if( event.Type == UIEVENT_BUTTONDOWN && m_pParent ) { m_pParent->SelectItem(this); } else if ( event.Type == UIEVENT_DBLCLICK && m_pParent ) { m_pParent->OnOptionDbClick(this); } CContainerUI::DoEvent(event); } bool CScrollOptionUI::OnBtnClose( void* pParam ) { TNotifyUI* pNotifyUI = (TNotifyUI*)pParam; if(pNotifyUI->sType == DUI_MSGTYPE_CLICK && m_pParent ) { m_pParent->DeleteItem(this); } return true; }
#pragma once class CScrollTabUI; class CScrollTabCallback { public: virtual void OnScrollTabCloseItem(CScrollTabUI* pTab, const int nDelIndex, const int nSelIndex) = 0; virtual void OnScrollTabSelectChange(CScrollTabUI* pTab, const int nUnSelIndex, const int nSelIndex) = 0; virtual void OnScrollTabAddItem(CScrollTabUI* pTab) = 0; virtual void OnScrollTabDbClick(CScrollTabUI* pTab, const int nIndex) = 0; }; class CScrollTabUI : public CContainerUI { public: CScrollTabUI(void); ~CScrollTabUI(void); CControlUI* AddTabItem(LPCTSTR lpText, bool bReset=false); void SelectItem(CControlUI* pItem); void DeleteItem(CControlUI* pItem); void DeleteItem(const int nIndex); void SetItemText(const int nIndex, LPCTSTR lpText); int GetItemCount()const { return m_pTabItems.size(); } void SetCallback(CScrollTabCallback* pCallback) { m_pCallback = pCallback; } void OnOptionDbClick(CControlUI* pOption); protected: virtual void SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue); virtual void Init(); virtual void SetPos(RECT rc); void ResetTabPos(); int GetTabItemIndex(CControlUI* pItem); bool OnBtnClickAdd(void* pParam); private: int m_nNorWidth; int m_nMinWidth; int m_nCurWidth; int m_nSelIndex; DWORD m_dwTabSelColor; DWORD m_dwTabNorColor; CButtonUI* m_pBtnAdd; vector<CControlUI*> m_pTabItems; CScrollTabCallback* m_pCallback; };
#include "StdAfx.h" #include "ScrollTabUI.h" #include "ScrollOptionUI.h" CScrollTabUI::CScrollTabUI(void) : m_nNorWidth(100) , m_nCurWidth(0) , m_nMinWidth(30) , m_dwTabSelColor(0xffffffff) , m_dwTabNorColor(0xfff0f0f0) , m_nSelIndex(-1) , m_pBtnAdd(NULL) , m_pCallback(NULL) { } CScrollTabUI::~CScrollTabUI(void) { } CControlUI* CScrollTabUI::AddTabItem( LPCTSTR lpText, bool bReset/*=false*/ ) { CScrollOptionUI* pTabItem = new CScrollOptionUI; if ( NULL == pTabItem ) return NULL; CDuiString strAttr; strAttr.Format(L"float=\"true\" bordercolor=\"#FF999999\" bordersize=\"1\" borderround=\"2,2\" text=\"%s\" tooltip=\"%s\"", lpText, lpText); pTabItem->ApplyAttributeList(strAttr); pTabItem->SetParent(this); if ( !Add(pTabItem) ) { delete pTabItem; return NULL; } if ( m_pTabItems.empty() ) m_nSelIndex = 0; m_pTabItems.push_back(pTabItem); if ( bReset ) ResetTabPos(); return pTabItem; } void CScrollTabUI::SelectItem( CControlUI* pItem ) { if ( m_nSelIndex>=0 && m_nSelIndex<m_pTabItems.size() ) { CControlUI* pCurItem = m_pTabItems[m_nSelIndex]; if ( pCurItem ) pCurItem->SetBkColor(m_dwTabNorColor); } pItem->SetBkColor(m_dwTabSelColor); int nUnSelIndex = m_nSelIndex; m_nSelIndex = GetTabItemIndex(pItem); if ( m_pCallback ) m_pCallback->OnScrollTabSelectChange(this, nUnSelIndex, m_nSelIndex); } void CScrollTabUI::SetAttribute( LPCTSTR pstrName, LPCTSTR pstrValue ) { if ( wcscmp(pstrName, L"TabWidth") == 0 ) { m_nNorWidth = _ttoi(pstrValue); return ; } if ( wcscmp(pstrName, L"MinTabWidth") == 0 ) { m_nMinWidth = _ttoi(pstrValue); return ; } if ( wcscmp(pstrName, L"TabSelColor") == 0 ) { if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue); LPTSTR pstr = NULL; m_dwTabSelColor = _tcstoul(pstrValue, &pstr, 16); return ; } if ( wcscmp(pstrName, L"TabNorColor") == 0 ) { if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue); LPTSTR pstr = NULL; m_dwTabNorColor = _tcstoul(pstrValue, &pstr, 16); return ; } CContainerUI::SetAttribute(pstrName, pstrValue); } void CScrollTabUI::Init() { m_pBtnAdd = new CButtonUI; CDuiString strAttr = L"float=\"true\" pos=\"0,0,0,0\" normalimage=\"file='tab_add.png' source='0,0,25,34' dest='0,0,25,30' \" \ hotimage=\"file='tab_add.png' source='25,0,50,34' dest='0,0,25,30' \" pushedimage=\"file='tab_add.png' source='50,0,75,34' dest='0,0,25,30' \" \ disabledimage=\"file='tab_add.png' source='75,0,100,34' dest='0,0,25,30' \" tooltip=\"新建\" "; m_pBtnAdd->ApplyAttributeList(strAttr); Add(m_pBtnAdd); m_pBtnAdd->OnNotify += MakeDelegate(this, &CScrollTabUI::OnBtnClickAdd); } void CScrollTabUI::DeleteItem( CControlUI* pItem ) { int nDelIndex = GetTabItemIndex(pItem); if ( nDelIndex == -1 ) return ; DeleteItem(nDelIndex); } void CScrollTabUI::DeleteItem( const int nIndex ) { if ( nIndex<0 || nIndex>=m_pTabItems.size() ) return ; Remove(m_pTabItems[nIndex]); m_pTabItems.erase(m_pTabItems.begin()+nIndex); int nCount = m_pTabItems.size(); if ( nCount>0 ) { if ( nIndex<m_nSelIndex ) m_nSelIndex--; else if ( nIndex == m_nSelIndex ) { m_nSelIndex = nCount-1; CControlUI* pItem = m_pTabItems[m_nSelIndex]; if ( pItem ) pItem->SetBkColor(m_dwTabSelColor); } ResetTabPos(); } else m_nSelIndex = -1; if ( m_pCallback ) m_pCallback->OnScrollTabCloseItem(this, nIndex, m_nSelIndex); } void CScrollTabUI::ResetTabPos() { int nCount = m_pTabItems.size(); if ( nCount == 0 ) { RECT rcItem = {m_rcItem.left, m_rcItem.top, 25, m_rcItem.bottom}; m_pBtnAdd->SetPos(rcItem); return ; } int nWidth = m_rcItem.right - m_rcItem.left-25; int nHeight= m_rcItem.bottom - m_rcItem.top; if ( nWidth/nCount < m_nMinWidth ) return ; if ( nCount*m_nNorWidth <= nWidth ) m_nCurWidth = m_nNorWidth; else m_nCurWidth = nWidth/nCount; RECT rcItem; for( size_t i=0; i<m_pTabItems.size(); ++i ) { rcItem.left = m_nCurWidth*i + m_rcItem.left; rcItem.top = 0 + m_rcItem.top; rcItem.right= rcItem.left + m_nCurWidth; rcItem.bottom = rcItem.top + nHeight; CControlUI* pItem = m_pTabItems[i]; pItem->SetPos(rcItem); if ( m_nSelIndex == i ) pItem->SetBkColor(m_dwTabSelColor); else pItem->SetBkColor(m_dwTabNorColor); } rcItem.left = rcItem.right; rcItem.right = rcItem.left + 25; m_pBtnAdd->SetPos(rcItem); } void CScrollTabUI::SetItemText( const int nIndex, LPCTSTR lpText ) { int nCount = m_pTabItems.size(); if ( 0 == nCount || nCount <= nIndex ) return ; CControlUI* pItem = m_pTabItems[nIndex]; if ( pItem ) { pItem->SetText(lpText); pItem->SetToolTip(lpText); } } int CScrollTabUI::GetTabItemIndex( CControlUI* pItem ) { int nIndex = -1; for ( size_t i=0; i<m_pTabItems.size(); ++i ) { if ( m_pTabItems[i] == pItem ) { nIndex = i; break; } } return nIndex; } bool CScrollTabUI::OnBtnClickAdd( void* pParam ) { TNotifyUI* pNotifyUI = (TNotifyUI*)pParam; if(pNotifyUI->sType != DUI_MSGTYPE_CLICK) return true; if ( m_pCallback ) m_pCallback->OnScrollTabAddItem(this); return true; } void CScrollTabUI::SetPos( RECT rc ) { CContainerUI::SetPos(rc); ResetTabPos(); } void CScrollTabUI::OnOptionDbClick(CControlUI* pOption) { if ( m_pCallback ) m_pCallback->OnScrollTabDbClick(this, m_nSelIndex); }子控件的消息都反射给父控件去处理,父控件同一管理所有子控件(计算宽度、设置选中、取消选中)。
下载管理没做,应该对下载回调进行处理,用自己封装的下载库来处理进度,并加下载管理窗口;
浏览记录,对用户输入网址进行匹配;
收藏夹,导入其他浏览器的收藏夹;
菜单项,各种设置。