分享个Duilib中基于wke的浏览器控件

概述

wke是基于谷歌chrome浏览器源代码的裁剪版本,大小仅仅只有10M左右,无需依赖其他的扩展库(跟CEF的一大堆大约40M的DLL来比简直爽呆了),就可以在本地使用谷歌内核快速加载网页。网上也有基于wke在Duilib 上扩展的控件代码,其实wke头文件挺清楚的了,接口一目了然,特别是JS与C++交互的函数更是容易看懂,也没什么难的,你也可以做到的。

代码

毕竟是裁剪库,有的功能还是没有接口来处理的(比如网页加载前、页面跳转、菜单消息……),头文件代码:

#ifndef __UIWKEWEBKIT_H_
#define __UIWKEWEBKIT_H_
#pragma once
#include "wke.h"
#include <string>
using std::wstring;

namespace DuiLib
{
	///////////////////////////////////////////
	//网页加载状态改变的回调
	class CWkeWebkitLoadCallback
	{
	public:
		virtual void	OnLoadFailed()=0;
		virtual void	OnLoadComplete()=0;
		virtual void	OnDocumentReady()=0;
	};
	///////////////////////////////////////////
	//网页标题、地址改变的回调
	class CWkeWebkitClientCallback
	{
	public:
		virtual void	OnTitleChange(const CDuiString& strTitle)=0;
		virtual void	OnUrlChange(const CDuiString& strUrl)=0;
	};

	class CWkeWebkitUI :
		public CControlUI,
		public wkeBufHandler
	{
	public:
		CWkeWebkitUI(void);
		~CWkeWebkitUI(void);
		virtual void	onBufUpdated (const HDC hdc,int x, int y, int cx, int cy);
		virtual LPCTSTR	GetClass()const;
		virtual LPVOID	GetInterface(LPCTSTR pstrName);
		virtual void	DoEvent(TEventUI& event);
		virtual void	DoPaint(HDC hDC, const RECT& rcPaint);
		virtual void	SetPos(RECT rc);
		virtual void	DoInit();
		virtual void	SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);
		//////////////////////////////////////
		const	wstring& GetUrl()const ;
		bool	CanGoBack() const;
		bool	GoBack();
		bool	CanGoForward() const;
		bool	GoForward();
		void	StopLoad();
		void	Refresh();
		wkeWebView	GetWebView();
		void	SetLoadCallback(CWkeWebkitLoadCallback* pCallback);
		CWkeWebkitLoadCallback* GetLoadCallback();
		void	Navigate(LPCTSTR lpUrl);
		void	LoadFile(LPCTSTR lpFile);
		void	LoadHtml(LPCTSTR lpHtml);
	protected:
		void	StartCheckThread();
		void	StopCheckThread();
		static	void OnTitleChange(const struct _wkeClientHandler* clientHandler, const wkeString title);
		static  void OnUrlChange(const struct _wkeClientHandler* clientHandler, const wkeString url);
	private:
		static int	m_bWebkitCount;
		HANDLE		m_hCheckThread;
		wstring		m_strUrl;
		wkeWebView	m_pWebView;
		wkeClientHandler	m_ClientHandler;
		CWkeWebkitLoadCallback*		m_pLoadCallback;
		CWkeWebkitClientCallback*	m_pClientCallback;
	};
}

#endif//__UIWKEWEBKIT_H_

实现部分代码:

#include "StdAfx.h"
#include "UIWkeWebkit.h"
#pragma comment(lib, "DuiEx/wke/wke")

namespace DuiLib{
///////////////////////////////////////////////////
//网页加载状态监测线程
DWORD WINAPI CheckThreadFun(LPVOID lpParam)
{
	CWkeWebkitUI* pWebkitUI=(CWkeWebkitUI*)lpParam;
	wkeWebView	pWebView=pWebkitUI->GetWebView();
	if ( NULL == pWebView )
		return 1;
	CWkeWebkitLoadCallback* pCallback=pWebkitUI->GetLoadCallback();
	if ( NULL == pCallback )
		return 1;
	bool bOver=false;
	while( !pWebView->isLoaded() )
	{
		if ( !bOver && pWebView->isDocumentReady() )
		{
			pCallback->OnDocumentReady();
			bOver=true;
		}
		if ( pWebView->isLoadFailed() )
		{
			pCallback->OnLoadFailed();
			return 1;
		}
		::Sleep(30);
	}
	if ( pWebView->isLoadComplete() )
		pCallback->OnLoadComplete();
	return 0;
}

//////////////////////////////////////////////////////
int CWkeWebkitUI::m_bWebkitCount=0;
CWkeWebkitUI::CWkeWebkitUI(void)
:m_pWebView(NULL)
,m_hCheckThread(NULL)
,m_pLoadCallback(NULL)
,m_pClientCallback(NULL)
{
	if ( 0 == m_bWebkitCount )
		wkeInit();
	m_pWebView=wkeCreateWebView();
	m_pWebView->setBufHandler(this);
	m_ClientHandler.onTitleChanged	=&CWkeWebkitUI::OnTitleChange;
	m_ClientHandler.onURLChanged	=&CWkeWebkitUI::OnUrlChange;
	m_bWebkitCount++;
}

CWkeWebkitUI::~CWkeWebkitUI(void)
{
	StopCheckThread();
	m_pManager->KillTimer(this);
	wkeDestroyWebView(m_pWebView);
	m_bWebkitCount--;
	if ( 0 == m_bWebkitCount )
		wkeShutdown();
}

LPCTSTR CWkeWebkitUI::GetClass() const
{
	return L"WkeWebkitUI";
}

LPVOID CWkeWebkitUI::GetInterface( LPCTSTR pstrName )
{
	if( _tcscmp(pstrName, _T("WkeWebkit")) == 0 )
		return static_cast<CWkeWebkitUI*>(this);
	return CControlUI::GetInterface(pstrName);
}

void CWkeWebkitUI::DoEvent( TEventUI& event )
{
	switch( event.Type )
	{
	case UIEVENT_SETFOCUS:
		if ( m_pWebView ) m_pWebView->focus(); break;
	case UIEVENT_KILLFOCUS:
		if ( m_pWebView ) m_pWebView->unfocus(); break;
	case UIEVENT_WINDOWSIZE:
		if ( m_pWebView ) m_pWebView->resize(GET_X_LPARAM(event.lParam), GET_Y_LPARAM(event.lParam)); break;
	case UIEVENT_CHAR:
		{
			if ( NULL == m_pWebView ) break;
			unsigned int charCode = event.wParam;
			unsigned int flags = 0;
			if (HIWORD(event.lParam) & KF_REPEAT)
				flags |= WKE_REPEAT;
			if (HIWORD(event.lParam) & KF_EXTENDED)
				flags |= WKE_EXTENDED;
			bool bHandled=m_pWebView->keyPress(charCode, flags, false);
			if ( bHandled )
				return ;
			break;
		}
	case UIEVENT_KEYDOWN:
		{
			if ( NULL == m_pWebView ) break;
			unsigned int flags = 0;
			if (HIWORD(event.lParam) & KF_REPEAT)
				flags |= WKE_REPEAT;
			if (HIWORD(event.lParam) & KF_EXTENDED)
				flags |= WKE_EXTENDED;
			bool bHandled=m_pWebView->keyDown(event.wParam, flags, false);
			if ( event.wParam == VK_F5 )
				Refresh();
			if ( bHandled )
				return ;
			break;
		}
	case UIEVENT_KEYUP:
		{
			if ( NULL == m_pWebView ) break;
			unsigned int flags = 0;
			if (HIWORD(event.lParam) & KF_REPEAT)
				flags |= WKE_REPEAT;
			if (HIWORD(event.lParam) & KF_EXTENDED)
				flags |= WKE_EXTENDED;
			bool bHandled=m_pWebView->keyUp(event.wParam, flags, false);
			if ( bHandled )
				return ;
			break;
		}
	case UIEVENT_CONTEXTMENU:
		{
			if ( NULL == m_pWebView ) break;
			unsigned int flags = 0;
			if (event.wParam & MK_CONTROL)
				flags |= WKE_CONTROL;
			if (event.wParam & MK_SHIFT)
				flags |= WKE_SHIFT;
			if (event.wParam & MK_LBUTTON)
				flags |= WKE_LBUTTON;
			if (event.wParam & MK_MBUTTON)
				flags |= WKE_MBUTTON;
			if (event.wParam & MK_RBUTTON)
				flags |= WKE_RBUTTON;
			bool handled = m_pWebView->contextMenuEvent(event.ptMouse.x, event.ptMouse.y, flags);
			if ( handled )
				return ;
			break;
		}
	case UIEVENT_MOUSEMOVE:
	case UIEVENT_BUTTONDOWN:
	case UIEVENT_BUTTONUP:
	case UIEVENT_RBUTTONDOWN:
	case UIEVENT_DBLCLICK:
		{
			HWND hWnd=m_pManager->GetPaintWindow();
			if ( event.Type == UIEVENT_BUTTONDOWN )
			{
				::SetFocus(hWnd);
				SetCapture(hWnd);
			}
			else if ( event.Type == UIEVENT_BUTTONUP )
				ReleaseCapture();
			unsigned int flags = 0;
			if (event.wParam & MK_CONTROL)
				flags |= WKE_CONTROL;
			if (event.wParam & MK_SHIFT)
				flags |= WKE_SHIFT;

			if (event.wParam & MK_LBUTTON)
				flags |= WKE_LBUTTON;
			if (event.wParam & MK_MBUTTON)
				flags |= WKE_MBUTTON;
			if (event.wParam & MK_RBUTTON)
				flags |= WKE_RBUTTON;
			UINT uMsg=0;
			switch ( event.Type )
			{
			case UIEVENT_BUTTONDOWN:	uMsg=WM_LBUTTONDOWN; break;
			case UIEVENT_BUTTONUP:		uMsg=WM_LBUTTONUP; break;
			case UIEVENT_RBUTTONDOWN:	uMsg=WM_RBUTTONDOWN; break;
			case UIEVENT_DBLCLICK:		uMsg=WM_LBUTTONDBLCLK; break;
			case UIEVENT_MOUSEMOVE:		uMsg=WM_MOUSEMOVE; break;
			}
			bool bHandled = m_pWebView->mouseEvent(uMsg, event.ptMouse.x-m_rcItem.left, 				event.ptMouse.y-m_rcItem.top, flags);
			if ( bHandled )
				return ;
			break;
		}
	case UIEVENT_TIMER:
		if ( m_pWebView )
			m_pWebView->tick();
		break;
	case UIEVENT_SCROLLWHEEL:
		{
			POINT pt;
			pt.x = LOWORD(event.lParam);
			pt.y = HIWORD(event.lParam);
			int nFlag=GET_X_LPARAM(event.wParam);
			int delta = (nFlag==SB_LINEDOWN)?-120:120;
			unsigned int flags = 0;
			if (event.wParam & MK_CONTROL)
				flags |= WKE_CONTROL;
			if (event.wParam & MK_SHIFT)
				flags |= WKE_SHIFT;
			if (event.wParam & MK_LBUTTON)
				flags |= WKE_LBUTTON;
			if (event.wParam & MK_MBUTTON)
				flags |= WKE_MBUTTON;
			if (event.wParam & MK_RBUTTON)
				flags |= WKE_RBUTTON;
			bool handled = m_pWebView->mouseWheel(pt.x, pt.y, delta, flags);
			if ( handled )
				return ;
			break;
		}
	default:
		CControlUI::DoEvent(event); break;
	}
}

void CWkeWebkitUI::DoPaint( HDC hDC, const RECT& rcPaint )
{
	if ( m_pWebView )
	{
		RECT rcInsert;
		IntersectRect(&rcInsert, &m_rcItem, &rcPaint);
		m_pWebView->paint(hDC, rcInsert.left, rcInsert.top, 			rcInsert.right-rcInsert.left, rcInsert.bottom-rcInsert.top, 			rcInsert.left-m_rcItem.left, rcInsert.top-m_rcItem.top, true);
	}
}

void CWkeWebkitUI::onBufUpdated( const HDC hdc,int x, int y, int cx, int cy )
{
	RECT rcValide={ x, y, x+cx, y+cy };
	::OffsetRect(&rcValide, m_rcItem.left, m_rcItem.top);
	HWND hWnd=m_pManager->GetPaintWindow();
	::InvalidateRect(hWnd, &rcValide, TRUE);
}

void CWkeWebkitUI::Navigate( LPCTSTR lpUrl )
{
	if ( m_pWebView )
	{
		m_pWebView->loadURL(lpUrl);
		StartCheckThread();
	}
}

void CWkeWebkitUI::SetPos( RECT rc )
{
	CControlUI::SetPos(rc);
	if ( m_pWebView )
		m_pWebView->resize(rc.right-rc.left, rc.bottom-rc.top);
}

void CWkeWebkitUI::DoInit()
{
	if ( !m_strUrl.empty() )
		Navigate(m_strUrl.c_str());
	m_pManager->SetTimer(this, 100, 100);
}

void CWkeWebkitUI::StartCheckThread()
{
	StopCheckThread();
	m_hCheckThread=::CreateThread(NULL, 0, CheckThreadFun, this, 0, NULL);
}

void CWkeWebkitUI::StopCheckThread()
{
	if ( m_hCheckThread )
	{
		if ( ::WaitForSingleObject(m_hCheckThread, 10) != WAIT_OBJECT_0 )
			::TerminateThread(m_hCheckThread, 0);
		::CloseHandle(m_hCheckThread);
		m_hCheckThread = NULL;
	}
}

bool CWkeWebkitUI::CanGoBack() const
{
	return m_pWebView?m_pWebView->canGoBack():false;
}

bool CWkeWebkitUI::GoBack()
{
	return m_pWebView?m_pWebView->goBack():false;
}

bool CWkeWebkitUI::CanGoForward() const
{
	return m_pWebView?m_pWebView->canGoForward():false;
}

bool CWkeWebkitUI::GoForward()
{
	return m_pWebView?m_pWebView->goForward():false;
}

void CWkeWebkitUI::StopLoad()
{
	if ( m_pWebView )
		m_pWebView->stopLoading();
}

void CWkeWebkitUI::Refresh()
{
	if ( m_pWebView )
	{
		StopCheckThread();
		m_pWebView->reload();
		StartCheckThread();
	}
}

wkeWebView CWkeWebkitUI::GetWebView()
{
	return m_pWebView;
}

void CWkeWebkitUI::SetLoadCallback( CWkeWebkitLoadCallback* pCallback )
{
	m_pLoadCallback=pCallback;
}

CWkeWebkitLoadCallback* CWkeWebkitUI::GetLoadCallback()
{
	return m_pLoadCallback;
}

void CWkeWebkitUI::OnTitleChange( const struct _wkeClientHandler* clientHandler, const wkeString title )
{

}

void CWkeWebkitUI::OnUrlChange( const struct _wkeClientHandler* clientHandler, const wkeString url )
{

}

void CWkeWebkitUI::LoadFile( LPCTSTR lpFile )
{
	if ( m_pWebView )
		m_pWebView->loadFile(lpFile);
}

void CWkeWebkitUI::LoadHtml( LPCTSTR lpHtml )
{
	if ( m_pWebView )
		m_pWebView->loadHTML(lpHtml);
}

const wstring& CWkeWebkitUI::GetUrl() const
{
	return m_strUrl;
}

void CWkeWebkitUI::SetAttribute( LPCTSTR pstrName, LPCTSTR pstrValue )
{
	if ( _tcscmp(pstrName, _T("url")) == 0 )
		m_strUrl = pstrValue;
	else
		CControlUI::SetAttribute(pstrName, pstrValue);
}

}

解析:

主要处理的就是消息部分,把这个区域的那种消息分发给wke的接口去处理。另外就是加了个线程,检测网页加载状态,通过回调通知网页加载完成、失败、DOC完成(需要用户先初始化回调指针才会通知用户)。

控件定义完成后,我们需要来配置XML了:

<WkeWebkit name="webkit1" url="http://192.168.1.20:92/?mainctl=chrome&version=1.2.3"/>

放在一个布局里面,指定URL即可,你也可以加上其他属性然后在SetAttribute中对这些属性进行初始化。

运行程序,一个无窗口的chrome内核网页控件就展示出来了:

后记

wke加载网页只能用于展示以及JS交互处理,毕竟裁剪后还是要失去很多其他功能的,对于chrome内核10M的大小已经是相当的不错了,另外还有一个EaWebkit也是基于chrome的扩展,编译成DLL后只有6M左右,也是开源的,大家可以网上看看。

时间: 2024-10-05 05:00:18

分享个Duilib中基于wke的浏览器控件的相关文章

Duilib中带有权重的灵活控件排列实现(一)

在开发播放器软件过程中,因为窗口的大小是可变的,为了让控制栏部分的控件(播放,上一集,下一集,全屏,字幕等)适应窗口的尺寸的变化而显示隐藏,产品经理会定义一系列的规则,好让在任何时候都最核心的功能提供给用户使用. 先列一下产品经理给予的需求: 两边往中间缩,保证左侧LOGO和右侧X最优先显示. 顶部隐藏优先级:搜索栏,换肤,意见反馈,播放记录,最小化,最大化 底部隐藏优先级:全屏,画质增强,无痕,打开文件,播放顺序,音量条 在处理这个需求过程中,前人也尝试了一些方法,比较通过全float绝对布局

duilib Webkit内核dui化浏览器控件

參考http://blog.csdn.net/zhuhongshu/article/details/38540711 改进: 1.跟其它duilib控件一样,不包括窗体 2.将onURLChanged和onTitleChanged发送到到Notify里处理 效果: 不足的地方: 1.改变大小时会闪屏(等大神来改进) 2.contextMenuEvent没反应,原样例也是这种 源代码里的duilib是截至发表时最新的. duilib:https://github.com/duilib/duilib

基于wke封装的duilib的webkit浏览器控件,可以c++与js互交,源码及demo下载地址

转载请说明原出处,谢谢~~ 前些日子用wke内核封装了duilib的webkit浏览器控件,好多群里朋友私聊我希望可以我公布源码,今天把这个控件的源码和使用demo公布.其实这个控件封装起来没什么难度,我只是按照原来作者的demo,把相应的消息封装成duilib对应的. 在此首先要感谢wke内核的作者BlzFans以及soui2界面库的作者flyhigh,BlzFans精简了webkit内核后封装为wke并公布了源码,flyhigh对wke进行处理让他更容易移植到dui工程中.wke内核10M大

duilib 的IE浏览器控件去边框和去滚动栏的代码

转载请说明原出处,谢谢~~ 近些天在duilib群里常常有朋友问起,怎么让duilib的IE控件能够去边框.去滚动栏的问题,或者是怎样去控件IE控件的行为.为了避免反复的回答,我就写一篇博文,把处理方法说明一下. duilib中有Webbrowser控件,是继承ActivexUI控件后针对IE进行的封装.使用IE控件的话就用他了. 这个控件留了一个接口名为SetWebBrowserEventHandler,这个函数用了指定一个事件处理器,来控制IE的行为. 而这个函数须要一个CWebBrowse

在web浏览器窗口中编辑报表的报表控件Stimulsoft Reports.Web

Stimulsoft Reports.Web是一个报表工具,适用于Web的报表生成器控件.其设计的目的在于通过Web浏览器创建和渲染报表.您可以创建报表,显示报表,打印报表,导出报表. Stimulsoft Reports.Web将提供完整的报表创建周期,从报表模板开始到在浏览器中显示报表为止.这一过程可在web浏览器未被关闭时完成.Stimulsoft Reports.Web是第一款可以让您直接在Web中编辑报表的报表工具.在您的客户端的机器里不需要安装.Net框架.ActiveX控件或其他特

duilib 的IE浏览器控件去边框和去滚动条的代码

近些天在duilib群里经常有朋友问起,怎么让duilib的IE控件可以去边框,去滚动条的问题,或者是如何去控件IE控件的行为.为了避免重复的回答,我就写一篇博文,把处理方法说明一下. duilib中有Webbrowser控件,是继承ActivexUI控件后针对IE进行的封装,使用IE控件的话就用他了.这个控件留了一个接口名为SetWebBrowserEventHandler,这个函数用了指定一个事件处理器,来控制IE的行为.而这个函数需要一个CWebBrowserEventHandler对象指

使用VC2008中ATL开发浏览器控件

http://blog.csdn.net/cnjet/article/details/6218355 使用VC2008中ATL开发浏览器控件 2011.03.02 [email protected] 介绍 本文将介绍使用VC2008中的ATL开发一个用于网络部署的cab控件包的过程. 建立ATL项目 打开VS2008,建立一个ATL项目,如下图: 考虑到简介性,选择了"Allow merging of proxy/stub code" 添加ATL控件 (建议先编译一下真个project

基于jQuery 常用WEB控件收集

Horizontal accordion: jQuery 基于jQuery开发,非常简单的水平方向折叠控件. Horizontal accordion: jQuery jQuery-Horizontal Accordion 具有XBOX360 blade界面风格的水平方向Accordion. jQuery-Horizontal Accordion AutoComplete-JQuery jQuery插件易于集成到现在的表单中(Form). AutoComplete-JQuery Facebook

一些基于jQuery开发的控件

基于jQuery开发,非常简单的水平方向折叠控件.主页:http://letmehaveblog.blogspot.com/2007/10/haccordion-simple-horizontal-accordion.html (无法找到)下载:http://letmehaveblog.blogspot.com/2007/10/haccordion-simple-horizontal-accordion.html 示例:http://letmehaveblog.blogspot.com/2007