使用Libcef+Duilib创建自己的Chrome内核浏览器

前言:

编译Chrome开源代码是一件很恐怖的事情,代码庞大,还需要各种工具配合。在windows上快速开发chrome内核网页程序,Libcef是一个很好的选择。最近趁空闲时间,写了一个简单的浏览器,很多功能都没有完善,不知道以后还会不会继续写了,PC端确实是萎了。

1、Libcef 的使用

在前面的几篇文章中大概介绍了下Libcef的使用,很多时候我们都会遇到各种问题,建议去看看它的接口函数声明,里面的注释写的非常清楚。

libCEF中C++与JavaScript的交互调

Windows上使用CEF嵌入基于chrome内核浏览器小例

2、大概的要点

程序运行截图

使用Libcef+Duilib创建自己的Chrome内核浏览器_第1张图片

使用Libcef+Duilib创建自己的Chrome内核浏览器_第2张图片

首先需要解决的是浏览器的Tab控件,扩展Duilib控件,每一个Tab控件就是一个容器里面存放着一系列Item,根据Item的个数和Tab的尺寸来计算每一个Item 节点的宽度。

对于单个节点Item控件,里面又有一个子Button控件,也就是关闭按钮。对于这个Item的消息进行处理,包括选中、双击、关闭,把这些消息都转发到父控件Tab中去处理。Tab控件同一管理这些控件的哪一个是选中状态。

然后是Libcef控件的创建,Tab中点击Add按钮后,需要创建网页控件并加载到当前窗口中去。整个父窗口在大小发生变化时,又要通知里面所有的Libcef子窗口随之变化。

然后就是关闭时,要让所有的Libcef子进程都能正常退出,就必须按照Libef文档说的那样,在退出时调用CefQuitMessageLoop()。

3、部分源代码

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);
}
子控件的消息都反射给父控件去处理,父控件同一管理所有子控件(计算宽度、设置选中、取消选中)。

4、未完成的

下载管理没做,应该对下载回调进行处理,用自己封装的下载库来处理进度,并加下载管理窗口;

浏览记录,对用户输入网址进行匹配;

收藏夹,导入其他浏览器的收藏夹;

菜单项,各种设置。






你可能感兴趣的:(使用Libcef+Duilib创建自己的Chrome内核浏览器)