WIN32界面开发之四:CPaintManagerUI类构建
来源:互联网 发布:java reflection 编辑:程序博客网 时间:2024/06/06 00:48
转自:http://blog.csdn.net/harvic880925/article/details/9632613
前言:前面我们完成了对DUI雏形的构建,但大家有没有注意到一个问题,我们对消息的处理都是在用户构建的类(CStartPage)中,还有,为了在控件中可以实时刷新,所以每个控件都必须带有一个变量m_hwnd,来保存当前窗体的句柄,而且在每次发送EVENT消息时都要赋值,相当麻烦,所以,我们将这些控件都具有的一些操作和变量,全部都集合起来,封装成一个类,这个类就是CPaintManagerUI;
一、基本变量定义
我带大家想想,我们应该把什么功能集成到CPaintManagerUI中呢,也就是哪些功能是不需要用户做的呢,又有哪些功能是控件所共有的呢:
1、CStartPage中的HandleMessage中,对具体消息的处理部分,比如WM_PAITN,WM_LBUTTONDOWN……
2、控件的Notify机制,上节中,每个控件为了可以NOTIFY到当前窗体,每个控件都要保存一个当前窗体的this指针,相当烦琐
CPaintManagerUI类就是对于公共的成员变量及成员方法的集成,以减少代码量,提高代码重用性,所写的一个类;既然是将原有代码进行独立,所以,独立的同时,也必须将原代码中的变量根据CPaintManagerUI的需要传进来,有几个变量是必须需要的;
3、m_hwnd:当前窗口的句柄,SendMessage()时用到;
4、m_hInstance:当前应用程序的HINSTANCE实例,在创建m_ToolTip(提示条)时用到
5、this指针:SendNotify()时,要将侦听NOTIFY消息的窗体发送NOTIFY消息,所以要将当前窗体的THIS指针,传到CPaintManangerUI中,通过CPaintManangerUI::SetNotifier(this)设置;CPaintManangerUI在发送NOTIFY时,会将消息发送给所有的侦听窗体;
我贴出CPaintManagerUI的核心定义:
注意:在源码中定义的变量要比这里的多些,多余的那些变量主要是为了双缓冲绘图所定义的:
- class CPaintManagerUI
- {
- public:
- CPaintManagerUI();
- ~CPaintManagerUI();
- public:
- void Init(HWND hWnd);//set hwnd of the window
- HWND GetHwnd(){return m_hWnd;}
- //NOTIFY部分 the part of Notify
- void SendNotify(CControlUI* pControl, LPCTSTR pstrMessage, WPARAM wParam= 0, LPARAM lParam= 0);//send notify messages to all listerners;
- bool AddNotifier(INotifyUI* pControl);
- bool RemoveNotifier(INotifyUI* pControl);
- //控件树部分 control-tree set part
- bool AttachDialog(CControlUI* pControl);//set the root of the control-tree
- bool InitControls(CControlUI* pControl, CControlUI* pParent = NULL);//set the current manager virable to controls
- //消息处理部分 message-handler
- bool MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT& lRes);
- private:
- CStdPtrArray m_aNotifiers;//NOTIFY消息接收的指针队列 listerners array
- HWND m_hWnd;//主窗体的句柄 the hwnd of main window
- CControlUI* m_pRoot;//XML控件树的根结点 the root of the DLG control tree,in our app this variable always point to CDlialogUI
- };
跟上面的分析的一样,主要存储的几个部分及其对应函数,分别是:
1、窗体句柄m_hWnd,分别对应:Init(设置)、GetHwnd(获取)
看代码:
- void CPaintManagerUI::Init(HWND hWnd)
- {
- ASSERT(::IsWindow(hWnd));
- // Remember the window context we came from
- m_hWnd = hWnd;
- }
- HWND CPaintManagerUI::GetHwnd()
- {
- return m_hWnd;
- }
2、消息通知部分,虽然我们当前只有一个监听类(CStartPage),但我们不想写的太死,所以使用了链表,用到了链表,当然就有增加和删除结点的部分了,具体函数解析如下:
(1)、m_aNotifiers,要接收NOTIFY消息的窗体指针队列
(2)、AddNotifier(),增加到队列中;RemoveNotifier()从队列中删除
(3)、SendNotify(),发送消息到接收窗体的Notify()函数中。
实现代码讲解:
- bool CPaintManagerUI::AddNotifier(INotifyUI* pControl)
- {
- ASSERT(m_aNotifiers.Find(pControl)<0);
- return m_aNotifiers.Add(pControl);
- }
- bool CPaintManagerUI::RemoveNotifier(INotifyUI* pControl)
- {
- for( int i = 0; i < m_aNotifiers.GetSize(); i++ ) {
- if( static_cast<INotifyUI*>(m_aNotifiers[i]) == pControl ) {
- return m_aNotifiers.Remove(i);
- }
- }
- return false;
- }
- void CPaintManagerUI::SendNotify(CControlUI* pControl, LPCTSTR pstrMessage, WPARAM wParam /*= 0*/, LPARAM lParam /*= 0*/)
- {
- TNotifyUI Msg;
- Msg.pSender = pControl;
- Msg.sType = pstrMessage;
- Msg.wParam = 0;
- Msg.lParam = 0;
- Msg.ptMouse =m_ptLastMousePos;
- Msg.dwTimestamp = ::GetTickCount();
- // Send to all listeners
- for( int i = 0; i < m_aNotifiers.GetSize(); i++ ) {
- static_cast<INotifyUI*>(m_aNotifiers[i])->Notify(Msg);
- }
- }
3、由于我们的这个CPaintManagerUI包含控件共有属性的集成部分,所以我们必须将CPaintManagerUI与控件关联起来,而这两个函数AttachDialog()、InitControls()就是实现这些功能。
- bool CPaintManagerUI::AttachDialog(CControlUI* pControl)
- {
- ASSERT(::IsWindow(m_hWnd));
- // Remove the existing control-tree. We might have gotten inside this function as
- // a result of an event fired or similar, so we cannot just delete the objects and
- // pull the internal memory of the calling code. We'll delay the cleanup.
- if( m_pRoot != NULL ) {
- m_aDelayedCleanup.Add(m_pRoot);
- ::PostMessage(m_hWnd, WM_APP + 1, 0, 0L);
- }
- // Set the dialog root element
- m_pRoot = pControl;
- return InitControls(pControl);
- }
- bool CPaintManagerUI::InitControls(CControlUI* pControl, CControlUI* pParent /*= NULL*/)
- {
- ASSERT(pControl);
- if( pControl == NULL ) return false;
- pControl->SetManager(this, pParent != NULL ? pParent : pControl->GetParent());
- // We're usually initializing the control after adding some more of them to the tree,
- // and thus this would be a good time to request the name-map rebuilt.
- return true;
- }
AttachDialog(),首先判断m_pRoot是否为空,如果不为空,就发送自定义消息WM_APP+1,将其清空;然后将当前的控件树ROOT结点指针赋值为m_pRoot;
InitControls(),就是给所有控件的PaintManagerUI赋值,大家注意执行顺序,这里执行的其实是m_pRoot->SetManager(this,parent);在代码中,我们在两个地方实现了SetManager,一个在CControlUI,另一个是在CContainerUI,而我们的m_pRoot肯定是CDialogUI类型,CDialogUI派生自CContainerUI,CContainerUI派生自CControlUI,所以根据继承关系,会执行CContainerUI的SetManger;具体实现流程:
1、先声明一个变量,CPaintManagerUI* m_pManager;,放在CControlUI中,供CControlUI和CContainerUI关联;
2、CContainerUI的SetManger的具体实现:
- void CContainerUI::SetManager(CPaintManagerUI* pManager, CControlUI* pParent)
- {
- for( int it = 0; it < m_items.GetSize(); it++ ) {
- static_cast<CControlUI*>(m_items[it])->SetManager(pManager, this);
- }//先设置它所有的子结点 set all his children nodes' manager first
- //然后再设置自己 and then set his own's manager
- CControlUI::SetManager(pManager, pParent);
- }
- void CControlUI::SetManager(CPaintManagerUI* pManager, CControlUI* pParent)
- {
- m_pManager = pManager;
- m_pParent = pParent;
- }
二、EVNET消息处理
在上面讲完了CPaintManagerUI的具体实现以后,基本上就没有什么好讲的了。最后看下如何在CButtonUI中发送Notify消息。代码如下:- void CButtonUI::Event(TEventUI& event)
- {
- if( event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK )
- {
- if( ::PtInRect(&m_RectItem, event.ptMouse)) {
- m_uButtonState |= UISTATE_PUSHED | UISTATE_CAPTURED;
- m_pManager->SendNotify(this,L"click");
- Invalidate();
- }
- }
- if( event.Type == UIEVENT_MOUSEMOVE )
- {
- if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
- m_pManager->SendNotify(this,L"drag");
- Invalidate();
- }
- }
- }
三、重写CStartPage::HandleMessage
由于我们将消息处理函数封装到了CPaintManagerUI中,所以我们要对CStartPage的HandleMessage重新实现,具体代码如下:
- LRESULT CStartPage::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
- {
- if( uMsg == WM_CREATE ) {
- m_pm.Init(m_hWnd);
- CDialogBuilder builder;
- CControlUI* pRoot = builder.Create(GetDialogResource());
- ASSERT(pRoot && "Failed to parse XML");
- m_pm.AttachDialog(pRoot);
- m_pm.AddNotifier(this);
- SendMessage(GetHWND(),WM_PAINT,NULL,NULL);
- //return 0;
- }
- LRESULT lRes = 0;
- if( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) return lRes;
- return CWindowWnd::HandleMessage(uMsg, wParam, lParam);
- }
比如在WM_CREATE中,首先是用CPaintManagerUI 变量m_pm初始化,初始化内容包括:窗体句柄、控件树、增加THIS指针到notifier;
四、最后
最后就是消除原来放在控件里的m_hwnd和Notify相关的函数了;这里就不一一列举了,代码里我都加了将原来的代码加上双斜线作为删除了,一看就明白,就不说了。看源码吧。
由于本文只是集成类的实现,并没有涉及功能的改变,所以也就不再贴图了。
本文由HARVIC完成,如若转载,请标明出处,请大家尊重初创者的版权,谢谢!!
源文地址:http://blog.csdn.net/harvic880925/article/details/9632613
源码地址:http://download.csdn.net/detail/harvic880925/5843901
- WIN32界面开发之四:CPaintManagerUI类构建
- WIN32界面开发之四:CPaintManagerUI类构建
- WIN32界面开发之三:DUI雏形开发(一)
- WIN32界面开发之三:DUI雏形开发(二)
- WIN32界面开发之三:DUI雏形开发(一)
- WIN32界面开发之三:DUI雏形开发(二)
- WIN32界面开发之DUI雏形开发(一)
- WIN32界面开发之DUI雏形开发(二)
- WIN32界面开发之二:GDI+中的局部刷新技术
- WIN32界面开发之二:GDI+中的局部刷新技术
- 软件项目开发环境构建之四:Bitbucket4.10.1安装
- Android开发入门(四)之界面Activity
- WIN32界面开发之一:初试加载背景界面
- iPhone开发之创建简单界面视图的三种方式之二 使用Xcode4完全手动构建界面
- win32界面
- win32界面
- DuiLib(6)——界面管家CPaintManagerUI的函数简介
- MFC框架界面开发(四):文档类
- PlagueScanner: An Open Source Multiple AV Scanner
- Boost相关链接
- 开启Windows 7远程桌面功能的做法
- Ubuntu搭建svn服务器(Subversion+Apache配置)
- java 异常捕获注意事项
- WIN32界面开发之四:CPaintManagerUI类构建
- IntelliJ IDEA使用心得
- C++中指针和引用的区别
- 假期-2015-1-25
- duilib库的点九技术
- Windows7环境下搭建Cocos2d-x3.3环境并配置android交叉编译环境
- iOS XMPP Framework 01 - Hello World
- 怎么样防止你的网站文章被非法复制,保存,或者查看源代码
- 工作中遇到的shell脚本知识(1)