首页 > REDM基础教程 > REDM基础教程8-DUI子控件事件消息分发
2016十月31

REDM基础教程8-DUI子控件事件消息分发

[隐藏]

根据前面一节,我们知道,DUI子控件的模拟窗口消息是通过ProcessDuiMessage来分发的,这一节我们来讨论DUI子控件的事件消息分发

  修改后的Test工程代码下载:

Test.zip

   

1.事件消息分发的两种方式

我们的MyTest工程,为什么点击关闭按钮会关闭呢?这一切都来源于事件消息分发,

DM库的事件分发完全COPY自CEGUI,稍做了下改变,比如事件ID不需要提前注册

我们就以按钮点击事件为例:

DUI子控件处理WM_LBUTTONUP消息(DUIWindow.h)

MSG_WM_LBUTTONUP(OnLButtonUp)

—>使用DV_FireEvent分发事件,注意,只有在DUI控件的ID或name不为空时,事件才能分发出去,不然,怎么区分事件是由哪个DUI控件发出来的呢

void DUIWindow::OnLButtonUp(UINT nFlags,CPoint pt)
	{
		.....
		if (0!=m_pDUIXmlInfo->m_iID
			||!m_pDUIXmlInfo->m_strName.IsEmpty())
		{
			DMEventCmdArgs Evt(this);// 按扭事件
			DV_FireEvent(Evt);
		}
	        .....
	}

DV_FireEvent函数内部代码如下:

	DMCode DUIWindow::DV_FireEvent(DMEventArgs &Evt)
	{
	        ....
		int iOldHandleCount = Evt.m_iHandleCount;
		m_EventMgr.FireEvent(Evt);			// 分发给注册消息,使用CEGUI的观察者注册方式
		if (Evt.m_iHandleCount>iOldHandleCount)
		{
			iErr = DM_ECODE_OK;			// 有函数处理了这个消息
			break;
		}
			
                  ....
		  iErr = GetContainer()->OnFireEvent(Evt);       // 此处进入了Event消息队列,Evt中包含了Event的发出者DUIWindow
		} while (false);
		return iErr;
	}

上面有两种处理方式:

1.我自己订阅事件,使用m_EventMgr.FireEvent分发

2.使用事件处理宏OnFireEvent接收消息

下面分别对这两种方式介绍

      

  

2.事件基类

/// <summary>
	///		事件基类,所有需注册的新事件必须先创建一个子类继承于它,并分配一个新的事件ID
	/// </summary>
	class DM_EXPORT DMEventArgs
	{
	public:
		DMEventArgs(DUIWindow *pSender);
		virtual ~DMEventArgs();
		virtual bool IsValid();								  // 判断是否合法,可发出去
		virtual UINT GetEventID() = 0;
		virtual LPCSTR GetEventName(){return NULL;};

	public:
		int								     m_iHandleCount;  ///< 当事件被处理时,m_iHandleCount增加
		int									 m_IdFrom;        ///< 事件发送者ID
		LPCWSTR								 m_szNameFrom;    ///< 事件发送者name
		DUIWindow*							 m_pSender;       ///< 产生事件的原始窗口对象
	};

所有的事件都继承于事件基类,每个事件都有一个唯一的ID

	/// <summary>
	///		事件ID
	/// </summary>
	enum DMEVT_ID
	{
		DMEVT_CMD			   = 10000,	
		DMEVT_HOVERCMD,
		....

如我们的按钮事件,使用的是DMEVT_CMD,这在本文最前面的代码中可以看到

	class DM_EXPORT DMEventCmdArgs:public DMEventArgs
	{
	public:
		DMEventCmdArgs(DUIWindow *pWnd):DMEventArgs(pWnd){}
		enum{EventID = DMEVT_CMD};
		UINT GetEventID(){return EventID;};
		LPCSTR GetEventName(){return EVEIDNAME(DMEVT_CMD);}
	};

    

   

3.自己订阅事件

blob.png

DM采用了CEGUI的观察者模式,允许自己订阅事件,原理也是非常简单:

1.DM把固定函数原型的函数fun注册到DMEventMgr中,对应某个事件ID

2.然后DMEventMgr.FireEvent分发时,会自动查找这个事件ID所有的注册fun,并调用它们

  

固定函数原型为:

DMCode XXXX(DMEventArgs* pEvent);

因为DMEventArgs中保存了事件ID,所以我们在函数内部做一次转换即可,注册支持全局函数和成员函数两种方式

我们来试着给关闭按钮再加一个订阅事件:

1.声明函数

DMCode OnClose(DMEventArgs* pEvent);

   

2.增加函数实现,在内部根据事件ID+控件name或id可以唯一确认这个事件是谁发过来的,当然,由于我们只是关闭按钮订阅了这个事件,所以也可以忽略前面这些判断条件

DMCode CMainWnd::OnClose(DMEventArgs* pEvent)
{
	if (DMEventCmdArgs::EventID== pEvent->GetEventID())// DMEVT_CMD这个事件ID
	{
		DMEventCmdArgs *pEvt = (DMEventCmdArgs*)pEvent;// 转换成实际的ID对应的类型
		if (0 == _wcsicmp(pEvt->m_szNameFrom,L"closebutton"))// 这个消息是closebutton这个name的控件发出来的
		{
			DestroyWindow(); 
		}
	}
	return DM_ECODE_OK;
}

   

3.在OnInitDialog中为关闭按钮订阅DMEVT_CMD这个事件,这里仅为关闭按钮订阅了这个事件,所以如2所述,判断事件ID+控件name或id的代码可以忽略

BOOL CMainWnd::OnInitDialog(HWND wndFocus, LPARAM lInitParam)
{
	DUIButton* pBtn = FindChildByNameT<DUIButton>(L"closebutton");
	if (pBtn)
	{
	    pBtn->m_EventMgr.SubscribeEvent(DMEventCmdArgs::EventID, Subscriber(&CMainWnd::OnClose, this));
	}
	return TRUE;
}

注意这里使用了DUIButton,所以需要在StdAfx.h中

#include "DUIButton.h"

  

我们运行一下,是不是会先跳到我们的订阅事件中~

    

   

4.使用事件处理宏

在最上面的介绍中,第二种方式是:我们使用事件消息宏OnFireEvent接收消息,其代码在DMHWnd(主窗口)中

	DMCode DMHWnd::OnFireEvent(DMEventArgs &Evt)
	{
		return DMHandleEvent(&Evt);
	}

所以事件消息宏分发使用的函数为DMHandleEvent

  

以MainWnd.cpp最上面的转换为例:

BEGIN_EVENT_MAP(CMainWnd)
	EVENT_NAME_COMMAND(L"closebutton",OnClose)
	EVENT_NAME_COMMAND(L"maxbutton",OnMaximize)
	EVENT_NAME_COMMAND(L"restorebutton",OnRestore)
	EVENT_NAME_COMMAND(L"minbutton", OnMinimize)
END_EVENT_MAP()

同样使用DMMacro.exe转换

DMCode CMainWnd::DMHandleEvent(DM::DMEventArgs *pEvt)
{ 
	DMCode iErr = DM_ECODE_FAIL;
	do
	{
		UINT  uCode = pEvt->GetEventID();
		if (DM::DMEVT_CMD == uCode && IsValidString(pEvt->m_szNameFrom) && 0==_wcsicmp(pEvt->m_szNameFrom,L"closebutton"))
		{
			iErr = OnClose();
			break;
		}

		if (DM::DMEVT_CMD == uCode && IsValidString(pEvt->m_szNameFrom) && 0==_wcsicmp(pEvt->m_szNameFrom,L"maxbutton"))
		{
			iErr = OnMaximize();
			break;
		}
		if (DM::DMEVT_CMD == uCode && IsValidString(pEvt->m_szNameFrom) && 0==_wcsicmp(pEvt->m_szNameFrom,L"restorebutton"))
		{
			iErr = OnRestore();
			break;
		}

		if (DM::DMEVT_CMD == uCode && IsValidString(pEvt->m_szNameFrom) && 0==_wcsicmp(pEvt->m_szNameFrom,L"minbutton"))
		{
			iErr = OnMinimize();
			break;
		}

	} while (false);
	if (DM_ECODE_FAIL==iErr)
	{
		return __super::DMHandleEvent(pEvt);
	}
	return iErr;
}

    

可以看出,DMHandleEvent函数内部是通过事件ID+函数名或id来判断调用函数

经过前面的介绍,增加事件消息宏的方式如下:

1.在头文件中声明

DECLARE_EVENT_MAP()							// 事件分发映射宏,也可以使用BEGIN_EVENT_MAPT宏使事件处理在头文件

2.在CPP中定义

BEGIN_EVENT_MAP(CMainWnd)
	....
END_EVENT_MAP()

     

5.DUIItemPanel分发事件消息

  像DUIListBoxEx等使用DUIItemPanel的控件,它们的分发消息略有不同,比如我们点击DUIListBoxEx的某个Button,它的流程如下:

1.DUIWindow::OnLButtonUp(UINT nFlags,CPoint pt)触发,原生消息为DMEventCmdArgs

void DUIWindow::OnLButtonUp(UINT nFlags,CPoint pt)
{
     .....
     if (0!=m_pDUIXmlInfo->m_iID
   ||!m_pDUIXmlInfo->m_strName.IsEmpty())
  {
   DMEventCmdArgs Evt(this);
   DV_FireEvent(Evt);
  }
}

 2.DV_FireEvent调用GetContainer()分发消息

DMCode DUIWindow::DV_FireEvent(DMEventArgs &Evt)
{
    .....
   iErr = GetContainer()->OnFireEvent(Evt);// 此处进入了Event消息队列,Evt中包含了Event的发出者DUIWindow
}

3.GetContainer()得到的是DUIItemPanel对象,所以这里会调用:

DMCode DUIItemPanel::OnFireEvent(DMEventArgs &Evt)
 {
  DMEventOfPanelArgs EvtOf(this, &Evt);
  EvtOf.m_szNameFrom = m_pDUIWnd->GetName();
  EvtOf.m_IdFrom     = m_pDUIWnd->GetID();
  return m_pDUIWnd->DV_FireEvent(EvtOf);
 }

这里可以划重点:原生的DMEventCmdArgs会被包装成DMEventOfPanelArgs(EventID=DMEVT_OFPANEL)消息转发出去,原生消息位于DMEventOfPanelArgs::m_pOrgEvt


所以处理消息可以参考TGPDemo中的TGPMainWnd.h

DMCode OnListBoxEx(DMEventArgs *pEvt);

//
EVENT_HANDLER(DMEVT_OFPANEL,OnListBoxEx)

//
DMCode CTGPMainWnd::OnListBoxEx(DMEventArgs *pEvt)
{
 DMEventOfPanelArgs* pEvtOf = (DMEventOfPanelArgs*)pEvt;
 if (pEvtOf&&pEvtOf->m_pOrgEvt)
 {
  int eventid = pEvtOf->m_pOrgEvt->GetEventID();// 得到原始消息的EventId
  CStringW strName = pEvtOf->m_pOrgEvt->m_szNameFrom;// 得到原始控件的name
  if (eventid == DMEventCmdArgs::EventID)// 然后自己做判断是来自哪个控件的哪个eventid
		....

或者像设计器一样,把DMEventOfPanelArgs再转换成原始消息:

DMCode AddXml::s_DMHandleEvent(DM::DMEventArgs *pEvt)
{
 if (ms_pthis&&!ms_pthis->m_bMuted)
 {
  if (DMEventOfPanelArgs::EventID == pEvt->GetEventID())
  {
   DMEventOfPanelArgs* pEvent = (DMEventOfPanelArgs*)pEvt;
   return ms_pthis->DMHandleEvent(pEvent->m_pOrgEvt);/// 注意这里转的是m_pOrgEvt
  }
  else
  {
   return ms_pthis->DMHandleEvent(pEvt);// 转发
  }
 }
 return DM_ECODE_FAIL;
}



6.自定义分发事件消息

前面提到的都是怎么接收事件消息,1.事件订阅 2.事件宏

这里我们来看看怎么分发一个事件消息

1.定义一个事件ID,对应新的事件比如叫DMEventNewArgs吧

#define  DMEVT_NEWID    123456			 /// id不要和内置id冲突了,设置大点
class DMEventNewArgs:public DMEventArgs
{
public:
	DMEventNewArgs(DUIWindow *pWnd):DMEventArgs(pWnd),m_a(100){}
	enum{EventID = DMEVT_NEWID};
	UINT GetEventID(){return EventID;};
	LPCSTR GetEventName(){return EVEIDNAME(DMEVT_NEWID);}
public:
	int m_a;/// 新加一个值 
};

    

2.在某个DUI控件的事件响应函数中增加分发事件代码即可,事件ID不需要提前注册,DM库会在发送时自动注册,这和CEGUI不同

	DMEventNewArgs Evt(this);
	DV_FireEvent(Evt); 

当然,特别注意的是,这个DUI控件的name或id不能同时为空

   

   下一节教程:REDM基础教程9-消息分发练习1

文章作者:hgy413
本文地址:https://hgy413.com/3637.html
版权所有 © 转载时必须以链接形式注明作者和原始出处!

21 Responses to “REDM基础教程8-DUI子控件事件消息分发”

  1. #1 minecraft 回复 | 引用 Post:2018-10-04 19:51

    Inspiring story there. What happened after? Take care!

  2. #2 Coconut Oil Benefits 回复 | 引用 Post:2018-10-19 01:31

    Your means of telling the whole thing in this article is in fact fastidious, all be
    able to without difficulty understand it, Thanks a lot.

  3. #3 Coconut Oil Benefits 回复 | 引用 Post:2018-10-24 14:42

    I think what you composed was very reasonable.

    However, consider this, what if you composed a catchier title?
    I ain’t suggesting your information isn’t solid,
    but what if you added something that grabbed folk’s attention? I mean blog
    topic is kinda vanilla. You could peek at Yahoo’s home page and see how they create article
    headlines to grab people to open the links.
    You might add a video or a picture or two to get readers interested
    about everything’ve got to say. In my opinion, it could bring your posts a little bit more interesting.

  4. #4 Benefits of Coconut Oil 回复 | 引用 Post:2018-10-28 23:22

    Hi there to every one, the contents existing at this site are genuinely amazing for
    people knowledge, well, keep up the nice work fellows.

  5. #5 quest bars cheap 回复 | 引用 Post:2018-11-03 10:31

    What’s up everyone, it’s my first pay a visit at this website, and piece of writing is in fact fruitful for me,
    keep up posting these types of articles or reviews.

  6. #6 quest bars cheap 回复 | 引用 Post:2018-11-03 23:46

    Hi, I do think this is an excellent site. I stumbledupon it
    😉 I’m going to revisit yet again since I book-marked it.
    Money and freedom is the best way to change, may you be rich and continue to guide others.

  7. #7 Quest Bars Cheap 回复 | 引用 Post:2018-11-08 16:58

    What’s up mates, fastidious piece of writing and good urging commented here, I am really enjoying by these.

  8. #8 Sling TV 回复 | 引用 Post:2018-11-11 20:19

    It’s appropriate time to make some plans for the future and it’s time to
    be happy. I’ve read this post and if I could I wish to suggest you few interesting things or advice.
    Maybe you can write next articles referring to
    this article. I want to read more things about it!

  9. Way cool! Some extremely valid points! I appreciate you writing this article and also the rest of the site is really good.

  10. #10 Sling TV 回复 | 引用 Post:2018-11-13 19:31

    If you are going for finest contents like I do, only pay a
    visit this site everyday since it gives quality contents, thanks

  11. Wow, this piece of writing is nice, my sister is analyzing these
    kinds of things, so I am going to let know her.

  12. Sling tv coupons and promo codes for november 2018
    I am curious to find out what blog system you happen to be utilizing?
    I’m having some minor security problems with my latest blog and I’d like to find something more
    risk-free. Do you have any suggestions? Sling tv coupons and promo codes for
    november 2018

  13. I am sure this post has touched all the internet people, its really really good article
    on building up new blog.

  14. Hello, i think that i saw you visited my website thus
    i got here to return the favor?.I’m trying to
    to find issues to improve my website!I suppose its good enough to make use of
    a few of your ideas!!

  15. Very quickly this web page will be famous amid all blog viewers, due to
    it’s pleasant posts

  16. It’s a pity you don’t have a donate button! I’d definitely donate to this brilliant blog!
    I suppose for now i’ll settle for book-marking and
    adding your RSS feed to my Google account. I look forward
    to fresh updates and will talk about this site
    with my Facebook group. Chat soon!

  17. #17 descargar facebook 回复 | 引用 Post:2018-11-21 06:53

    Pretty nice post. I just stumbled upon your weblog and wished to say that I’ve
    truly enjoyed browsing your blog posts. In any case I will be subscribing to your rss feed and I hope you write again soon!

  18. #18 descargar facebook 回复 | 引用 Post:2018-12-06 12:54

    I was suggested this blog by my cousin. I am not sure whether this post is written by him as
    no one else know such detailed about my problem.
    You are amazing! Thanks!

  19. #19 there g 回复 | 引用 Post:2020-06-10 11:58

    Thank you for the auspicious writeup. It in reality was a amusement account
    it. Glance complex to more added agreeable from you!
    By the way, how could we communicate?

  20. #20 g 回复 | 引用 Post:2020-06-12 19:15

    I’ve been surfing online more than 2 hours today, yet I never
    found any interesting article like yours. It is pretty worth enough for me.
    In my opinion, if all website owners and bloggers made good content as you did, the
    net will be much more useful than ever before.

  21. #21 http://tinyurl.com 回复 | 引用 Post:2020-06-14 03:43

    Hi there, just wanted to mention, I loved this post.
    It was inspiring. Keep on posting!

发表评论