分享个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 voidOnLoadFailed()=0;virtual voidOnLoadComplete()=0;virtual voidOnDocumentReady()=0;};/////////////////////////////////////////////网页标题、地址改变的回调class CWkeWebkitClientCallback{public:virtual voidOnTitleChange(const CDuiString& strTitle)=0;virtual voidOnUrlChange(const CDuiString& strUrl)=0;};class CWkeWebkitUI :public CControlUI,public wkeBufHandler{public:CWkeWebkitUI(void);~CWkeWebkitUI(void);virtual voidonBufUpdated (const HDC hdc,int x, int y, int cx, int cy);virtual LPCTSTRGetClass()const;virtual LPVOIDGetInterface(LPCTSTR pstrName);virtual voidDoEvent(TEventUI& event);virtual voidDoPaint(HDC hDC, const RECT& rcPaint);virtual voidSetPos(RECT rc);virtual voidDoInit();virtual voidSetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue);//////////////////////////////////////constwstring& GetUrl()const ;boolCanGoBack() const;boolGoBack();boolCanGoForward() const;boolGoForward();voidStopLoad();voidRefresh();wkeWebViewGetWebView();voidSetLoadCallback(CWkeWebkitLoadCallback* pCallback);CWkeWebkitLoadCallback* GetLoadCallback();voidNavigate(LPCTSTR lpUrl);voidLoadFile(LPCTSTR lpFile);voidLoadHtml(LPCTSTR lpHtml);protected:voidStartCheckThread();voidStopCheckThread();staticvoid OnTitleChange(const struct _wkeClientHandler* clientHandler, const wkeString title);static void OnUrlChange(const struct _wkeClientHandler* clientHandler, const wkeString url);private:static intm_bWebkitCount;HANDLEm_hCheckThread;wstringm_strUrl;wkeWebViewm_pWebView;wkeClientHandlerm_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;wkeWebViewpWebView=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;elseCControlUI::SetAttribute(pstrName, pstrValue);}}

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

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

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

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

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

打掉的应是脆弱的铁屑,锻成的将是锋利的钢刀。

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

相关文章:

你感兴趣的文章:

标签云: