duilib源码探析之事件绑定

引言

之前自己写界面库的时候,未找到好方法响应消息,使用的是最笨的方式,在主窗口的响应函数中,判断是哪个子窗口,进而再判断是哪个按钮。

最近使用云信duilib,正好研究了下duilib按钮与响应绑定的方法。


duilib事件绑定

每个控件都可以单独设置自己的事件处理函数,一般在InitWindow方法中初始化各个控件的事件处理函数。每个控件都有许多形如Attach···的方法,比如按钮控件ButtonAttachMouseEnterAttachButtonDownAttachClick方法,他们分别用于指定控件鼠标进入、鼠标按下、鼠标单击的事件处理函数。

一个常见的例子:

void MyForm::InitWindow()
{
	ui::Button* btn_login = static_cast<ui::Button*>(FindControl(L"login_button"));
	btn_login->AttachClick(nbase::Bind(&MyForm::OnLoginClicked, this, std::placeholders::_1, true));
}

bool MyForm::OnLoginClicked(ui::EventArgs * msg)
{
	std::wstring name = msg->pSender->GetName();

	if (msg->Type == ui::kEventClick)
	{

		if (name == L"login_button")
		{
			DoLogin();
		}
	}
	return true;
}

本立而道生

很多东西不知道根本,总感觉很玄,不知道怎么实现,也不知道其能够做什么,不能做什么,为什么能这么做。当然了,很多东西也不必追究根本,而这一个事件绑定,对我而言,有必要探究一下。

跟踪AttachClick进去看看,这是一个模板类,在这个类里定义了AttachClick函数,


namespace ui
{
template<typename InheritType = Control>
class UILIB_API ButtonTemplate : public LabelTemplate<InheritType>
{
public:
	ButtonTemplate();

	virtual void Activate() override;
	virtual void HandleMessage(EventArgs& event) override;

	void AttachClick(const EventCallback& callback)	{ OnEvent[kEventClick] += callback;	}
};

#include "ButtonImpl.h"

typedef ButtonTemplate<Control> Button;
typedef ButtonTemplate<Box> ButtonBox;

}	// namespace ui

这个函数是这么定义的

void AttachClick(const EventCallback& callback)	{ 

OnEvent[kEventClick] += callback;	

}

其中kEventClick是定义在duilib/CORE/define.h中的消息类型,如:

//定义所有消息类型

enum EventType
{
	kEventInternalDoubleClick,
	kEventInternalMenu,
	kEventInternalSetFocus,
	kEventInternalKillFocus ,

	kEventNone,

	kEventFirst,

	kEventAll,
。。。

OnEvent[kEventClick]是数组的写法,也可能是MAP的写法。

这是定义在所有控件的基类Control中的一个成员变量。

protected:
EventMap OnEvent;
	EventMap OnXmlEvent;
	GifEventMap OnGifEvent;

EventMap是这种类型
typedef std::map<EventType, CEventSource> EventMap;

因此

OnEvent[kEventClick],指的是kEventClick单击事件所对应的事件处理方式CEventSource

CEventSource是这么定义的,继承自vector容器类,容器中保存着bool(ui::EventArgs*)类型的消息处理函数,重载了+操作符。

typedef std::function<bool(ui::EventArgs*)> EventCallback;

class CEventSource : public std::vector<EventCallback>
{
public:
	CEventSource& operator += (const EventCallback& item) 
	{
		push_back(item);
		return *this;
	}

	bool operator() (ui::EventArgs* param) const 
	{
		for (auto it = this->begin(); it != this->end(); it++) {
			if(!(*it)(param)) return false;
		}
		return true;
	}

};

到这里,大体明白点是怎么回事了,attackClick是将按钮的单击事件,与事件对应的响应函数,以map映射的方式关联在一起。

AttachClick(nbase::Bind(&MyForm::OnLoginClicked,this,std::placeholders::_1, true));









猜你喜欢

转载自blog.csdn.net/shuilan0066/article/details/79932509