DUILIB界面库使用介绍.doc_第1页
DUILIB界面库使用介绍.doc_第2页
DUILIB界面库使用介绍.doc_第3页
DUILIB界面库使用介绍.doc_第4页
DUILIB界面库使用介绍.doc_第5页
已阅读5页,还剩38页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Duilib界面库使用介绍一、Duilib简介Duilib是以DirectUI为技术原理开发的一款轻量级Windows桌面UI库,具有入门简单,使用方便等特点,在国内吸引了不少的开发者。其开发原型为国外大神viksoe的http:/www.viksoe.dk/code/windowless1.htm 文章中提供的源码,国内开源前辈以此为基础:修正Bug、优化程序结构、提高稳定性和易用性,是一款功能强大,使用方便的界面库。界面库使用XML来描述界面风格,界面布局,可以很方便的构建高效,绚丽的,非常易于扩展的界面。从而很好的将界面和逻辑分离,同时易于实现各种超炫的界面效果如换色,换肤,透明等。Duilib界面库的出现解决了使用传统MFC界面库开发软件不美观、界面细节处理不好、使用硬编码、开发效率低下、生成程序体积大等问题。国内的以下客户端都曾经以此为基础拓展并使用了duilib: 1. 百度杀毒2. 微信PC客户端3. 爱奇艺客户端4. 酷我音乐其他基于Duilib的软件不完全列表:百度: PPS 百度卫士 91助手腾讯: 企业微信阿里: 钉钉 支付宝安全控件 PP助手华为: 华为网盘书生云:书生企业云盘微软: 微软壁纸网易: 易信 云音乐 荒野行动PC版金山: 金山快盘京东: 咚咚cctv: cbox蘑菇街: TeamTalk火绒: 火绒安全软件盘古: 盘古越狱工具顺网: 网维大师 91y网狐: 网狐经典版墨迹风云: 墨迹天气zoomcloud: Zoom视频会议搜狗: 搜狗手机助手沃通: 沃通代码签名工具驱动人生: 驱动人生 人生日历维棠: 维棠深圳市北斗智研科技: 智能办公助手 ERP管理系统2、 Duilib原理DirectUI意为直接在父窗口上绘图(Paint on parent dc directly)。即子窗口不以窗口句柄的形式创建(windowless),只是逻辑上的窗口,绘制在父窗口之上。通俗来说就是在窗口上指定一块区域(仅仅是一个区域,不是一个实体控件)通过各种消息模拟一个控件的功能。完全可以在一个对话框类的OnMouseMove、OnLButtonDown等函数中模拟一个按钮出来。但是模拟的控件一多就混乱了,为了统一管理,逻辑上更清晰类似于实体控件。把每种控件封装成类处理各种消息,并通过自定义的消息分发机制把消息分发到各个模拟控件里。DuiLib 一部分技术特点界面与业务逻辑分离使用XML配置界面界面布局方式灵活多样强大的事件处理机制基于GDI和脏矩形的高效绘制技术支持多种资源方式,支持多种图片格式支持alpha混合,支持窗口透明支持动态切换资源位置方式换肤支持unicode内存占用小无第三方库依赖CPaintManagerUI - 管理控件的绘制以及消息处理分发等功能其中关联了真正的主窗口HWDN以及HOVER,FOCUS,CLICK等控件指针。CControlUI - 大多控件的基类。 包含控件各种属性,需要子类控件处理的消息的虚函数等。button响应消息过程1.CPaintManagerUI findcontrol,根据点找到CControlUI2.该控件调用虚函数的DoEvet(如按钮具体是改变自身一些flag)3.调用基类(CControlUI)的Invalidate.(此Invalidate是依次找父UI(layout之类)和当前区域相交结果,只刷新那一部分).4.m_pRoot调用DoPaint。从最下层依次调用有子关系的CControlUI的DoPaint。(涉及剪切,区域相交等)3、 运行流程Win32消息路由如下:消息产生。系统将消息排列到其应该排放的线程消息队列中。线程中的消息循环调用GetMessage(or PeekMessage)获取消息。传送消息TranslateMessage and DispatchMessage to 窗口过程(Windows procedure)。在窗口过程里进行消息处理#include ././DuiLib/UIlib.husing namespace DuiLib;#ifdef _DEBUG# ifdef _UNICODE# pragma comment(lib, ././Lib/DuiLib_ud.lib)# else# pragma comment(lib, ././Lib/DuiLib_d.lib)# endif#else# ifdef _UNICODE# pragma comment(lib, ././Lib/DuiLib_u.lib)# else# pragma comment(lib, ././Lib/DuiLib.lib)# endif#endifclass CFrameWnd : public CWindowWndpublic: virtual LPCTSTR GetWindowClassName() const return _T(FrameWnd); virtual void OnFinalMessage(HWND hWnd) delete this; ;int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nShowCmd ) / new一个窗口对象 CFrameWnd* pFrame = new CFrameWnd; / 注册窗口类、创建窗口 pFrame-Create(NULL, _T(sample01), UI_WNDSTYLE_FRAME, UI_WNDSTYLE_EX_FRAME, 100, 100, 800, 600, NULL); / 显示窗口、进入窗口消息循环 pFrame-ShowModal(); return 0;使用CFrameWnd继承自CWindowWnd,CWindowWnd必须实现的一个纯虚接口是GetWindowClassName来表明她的窗口类名。在OnFinalMessage中delete this是因为DuiLib中需要使用new来生成一个窗口,delete可以防止内存泄漏(在后面的DuiLib程序中可以看到都只有new而没有delete,这是因为DuiLib内部在窗口销毁时已经做了delete的操作)。以下是关键的几个方法: 1、创建窗口 HWND CWindowWnd:Create(HWND hwndParent, LPCTSTR pstrName, DWORD dwStyle, DWORD dwExStyle, int x, int y, int cx, int cy, HMENU hMenu) if( GetSuperClassName() != NULL & !RegisterSuperclass() ) return NULL; if( GetSuperClassName() = NULL & !RegisterWindowClass() ) return NULL; m_hWnd = :CreateWindowEx(dwExStyle, GetWindowClassName(), pstrName, dwStyle, x, y, cx, cy, hwndParent, hMenu, CPaintManagerUI:GetInstance(), this); ASSERT(m_hWnd!=NULL); return m_hWnd;在调用CreateWindowEx这个windows API前会先调用RegisterWindowClass注册窗口类。 2、显示窗口并进入消息循环UINT CWindowWnd:ShowModal() ASSERT(:IsWindow(m_hWnd); UINT nRet = 0; HWND hWndParent = GetWindowOwner(m_hWnd); :ShowWindow(m_hWnd, SW_SHOWNORMAL); :EnableWindow(hWndParent, FALSE); MSG msg = 0 ; while( :IsWindow(m_hWnd) & :GetMessage(&msg, NULL, 0, 0) ) if( msg.message = WM_CLOSE & msg.hwnd = m_hWnd ) nRet = msg.wParam; :EnableWindow(hWndParent, TRUE); :SetFocus(hWndParent); if( !CPaintManagerUI:TranslateMessage(&msg) ) :TranslateMessage(&msg); :DispatchMessage(&msg); if( msg.message = WM_QUIT ) break; :EnableWindow(hWndParent, TRUE); :SetFocus(hWndParent); if( msg.message = WM_QUIT ) :PostQuitMessage(msg.wParam); return nRet;先调用了ShowWindow去显示窗口,然后进入GetMessage消息循环。3、窗口过程 LRESULT CALLBACK CWindowWnd:_WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) CWindowWnd* pThis = NULL; if( uMsg = WM_NCCREATE ) LPCREATESTRUCT lpcs = reinterpret_cast(lParam); pThis = static_cast(lpcs-lpCreateParams); pThis-m_hWnd = hWnd; :SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(pThis); else pThis = reinterpret_cast(:GetWindowLongPtr(hWnd, GWLP_USERDATA); if( uMsg = WM_NCDESTROY & pThis != NULL ) LRESULT lRes = :CallWindowProc(pThis-m_OldWndProc, hWnd, uMsg, wParam, lParam); :SetWindowLongPtr(pThis-m_hWnd, GWLP_USERDATA, 0L); if( pThis-m_bSubclassed ) pThis-Unsubclass(); pThis-m_hWnd = NULL; pThis-OnFinalMessage(hWnd); return lRes; if( pThis != NULL ) return pThis-HandleMessage(uMsg, wParam, lParam); else return :DefWindowProc(hWnd, uMsg, wParam, lParam); 4、windows消息处理 LRESULT CDialogWnd:HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) LRESULT lRes = 0; BOOL bHandled = TRUE; switch( uMsg ) case WM_CREATE: lRes = OnCreate(uMsg, wParam, lParam, bHandled); break;case WM_CLOSE: lRes = OnClose(uMsg, wParam, lParam, bHandled); break;case WM_DESTROY: lRes = OnDestroy(uMsg, wParam, lParam, bHandled); break;case WM_NCACTIVATE: lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); break;case WM_NCCALCSIZE: lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); break;case WM_NCPAINT: lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); break;case WM_NCHITTEST: lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); break;case WM_SIZE: lRes = OnSize(uMsg, wParam, lParam, bHandled); break;case WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); break;case WM_SYSCOMMAND: lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); break; default: bHandled = FALSE; if( bHandled ) return lRes; if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes; return CWindowWnd:HandleMessage(uMsg, wParam, lParam);5、CPaintManagerUI消息处理 bool CPaintManagerUI:MessageHandlerImpl(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes) / Not ready yet? if( m_hWndPaint = NULL ) return false; SendAsyncNotify(); / Cycle through listeners for( int i = 0; i m_aMessageFilters.GetSize(); i+ ) bool bHandled = false; LRESULT lResult = static_cast(m_aMessageFiltersi)-MessageHandler(uMsg, wParam, lParam, bHandled); if( bHandled ) lRes = lResult; return true; / Custom handling of events switch( uMsg ) . case WM_LBUTTONDOWN: /edit close problem is solved in its doevent POINT pt = GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) ; m_ptLastMousePos = pt; CControlUI* pControl;if(m_pEventRClick != NULL) pControl = m_pEventRClick;else pControl = FindControl(pt);if( pControl = NULL )SetFocus(NULL);pControl = FindCaptureControl(pt);if(pControl)PostMessage(m_hWndPaint,WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(pt.x,pt.y);break;if( pControl-GetManager() != this ) break;pControl-SetFocus();SetCapture();m_pEventClick = pControl; TEventUI event = 0 ; event.Type = UIEVENT_BUTTONDOWN; event.pSender = pControl; event.wParam = wParam; event.lParam = lParam; event.ptMouse = pt; event.wKeyState = (WORD)wParam; event.dwTimestamp = :GetTickCount(); pControl-Event(event); break; . default: break; SendAsyncNotify(); return false;6、控件绘制&发送notify void CButtonUI:DoEvent(TEventUI& event)if( !IsMouseEnabled() & event.Type UIEVENT_MOUSEBEGIN & event.Type Event(event);else CLabelUI:DoEvent(event);return;.if( event.Type = UIEVENT_BUTTONDOWN | event.Type = UIEVENT_DBLCLICK )if( :PtInRect(&m_rcItem, event.ptMouse) & IsEnabled() ) m_uButtonState |= UISTATE_PUSHED | UISTATE_CAPTURED;Invalidate();return;if( event.Type = UIEVENT_MOUSEMOVE )if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) if( :PtInRect(&m_rcItem, event.ptMouse) ) m_uButtonState |= UISTATE_PUSHED;else m_uButtonState &= UISTATE_PUSHED;Invalidate();return;if( event.Type = UIEVENT_BUTTONUP )if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) if( :PtInRect(&m_rcItem, event.ptMouse) ) Activate();m_uButtonState &= (UISTATE_PUSHED | UISTATE_CAPTURED);Invalidate();return;if( event.Type = UIEVENT_CONTEXTMENU )if( IsContextMenuUsed() ) m_pManager-SendNotify(this, _T(menu), event.wParam, event.lParam);return;.CLabelUI:DoEvent(event);bool CButtonUI:Activate()if( !CControlUI:Activate() ) return false;if( m_pManager != NULL ) m_pManager-SendNotify(this, _T(click);return true;6、CPaintManagerUI执行notify通知 void CPaintManagerUI:SendNotify(CControlUI* pControl, LPCTSTR pstrMessage, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/, bool bAsync /*= false*/) TNotifyUI Msg; Msg.pSender = pControl; Msg.sType = pstrMessage; Msg.wParam = wParam; Msg.lParam = lParam; SendNotify(Msg, bAsync);void CPaintManagerUI:SendNotify(TNotifyUI& Msg, bool bAsync /*= false*/) Msg.ptMouse = m_ptLastMousePos; Msg.dwTimestamp = :GetTickCount();if( m_bUsedVirtualWnd )Msg.sVirtualWnd = Msg.pSender-GetVirtualWnd(); if( !bAsync ) / Send to all listeners if( Msg.pSender != NULL ) if( Msg.pSender-OnNotify ) Msg.pSender-OnNotify(&Msg); for( int i = 0; i m_aNotifiers.GetSize(); i+ ) static_cast(m_aNotifiersi)-Notify(Msg); else TNotifyUI *pMsg = new TNotifyUI; pMsg-pSender = Msg.pSender; pMsg-sType = Msg.sType; pMsg-wParam = Msg.wParam; pMsg-lParam = Msg.lParam; pMsg-ptMouse = Msg.ptMouse; pMsg-dwTimestamp = Msg.dwTimestamp; m_aAsyncNotify.Add(pMsg); 7、主界面程序初始化时,添加观察者对象到CPaintManagerUI中。LRESULT CDialogWnd:OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) LONG styleValue = :GetWindowLong(*this, GWL_STYLE); styleValue &= WS_CAPTION; :SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN); RECT rcClient; :GetClientRect(*this, &rcClient); :SetWindowPos(*this, NULL, rcClient.left, rcClient.top, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, SWP_FRAMECHANGED); m_pm.Init(m_hWnd);m_preMsgHandler.SetManager(&m_pm);m_pm.AddPreMessageFilter(&m_preMsgHandler); CDialogBuilder builder; CControlUI* pRoot = builder.Create(m_strXml.GetData(), (UINT)0, m_DialogBuilderCallback, &m_pm); ASSERT(pRoot & Failed to parse XML); m_pm.AttachDialog(pRoot); m_pm.AddNotifier(this); SIZE szInitWindowSize = m_pm.GetInitSize(); if( szInitWindowSize.cx != 0 ) :SetWindowPos(*this, NULL, 0, 0, szInitWindowSize.cx, szInitWindowSize.cy, SWP_NOZORDER | SWP_NOMOVE); InitCommonBottons(); Init(); return 0;8. 响应观察者notify消息void CDialogWnd:Notify(TNotifyUI& msg) if( msg.sType = _T(windowinit) ) else if( msg.sType = _T(click) ) 事件类型:消息说明Senderclick鼠标点击CButtonUIdropdown下拉显示CComboUIheaderclick点击列标题CListHeaderItemUIitemactivateCListElementUI、CListContainerElementUIitemclick单击选项CListLabelElementUI、CListContainerElementUIitemselect选择选项CComboUI、CListUIkillfocus失去焦点CControlUIlinkCTextUI、CListTextElementUImenuCButtonUI、CControlUIreturn回车CEditWnd、CRichEditUIscroll滚动CScrollBarUIselectchanged变更选项COptionUIsetfocus获得焦点CControlUIshowactivexCActiveXUItabselect标签页被选中CTabLayoutUItimerCControlUIvaluechanged值发生变化CSliderUIwindowinit窗体初始化4、 界面布局布局:名称说明VerticalLayout垂直布局:其内元素按照竖直方式排列HorizontalLayout水平布局:其内元素按照水平方

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论