郑州网站建设 郑州网站设计,网站建设按年收费吗,微动网站建设,伊春网站推广文中若有代码、术语等错误#xff0c;欢迎指正 文章目录 008、事件系统-设计009、事件系统-自定义事件前言自定义事件类与使用声明与定义类代码包含头文件使用事件 事件调度器代码 C知识#xff1a;FunctionBind用法function基本使用 012、事件系统-DemoLayer用EventDispache… 文中若有代码、术语等错误欢迎指正 文章目录 008、事件系统-设计009、事件系统-自定义事件前言自定义事件类与使用声明与定义类代码包含头文件使用事件 事件调度器代码 C知识FunctionBind用法function基本使用 012、事件系统-DemoLayer用EventDispacher拦截处理事件56难理解Application设置window回调函数与回调123Application将事件传给Layer4与整个事件系统流程  008、事件系统-设计 此节目的 理清顺序和设计才能更好的编码  设计如图  声明 图是我自己缝合的流程与大意没错但是不符合软件工程对应图的规范。 大致是根据视频草稿图与大意画的  使用时序图简单表示   使用类图详细表示 在软件工程中类图没有消息传递的不符合规范但大意是这样    
009、事件系统-自定义事件 
前言 此节目的 由008节的计划窗口事件图中的2.3将glfw窗口事件分组成自己系统的事件Event即写出对应glfw窗口事件的自定义事件Event类。  事件最终的设计 为了简便自定义事件是立即处理事件没有缓冲事件。 缓冲事件键盘a一直按下第一个立刻输出顿了一下才一直输出。  glfw窗口事件  窗口相关事件 重新调整大小、窗口关闭等  鼠标事件 移动、滚动、按下  键盘事件 键盘按下、释放   类图   
自定义事件类与使用 
声明与定义类代码 声明 由于类过多只写几个类  Event /*为了简便自定义事件是立即处理事件没有缓冲事件。缓冲事件键盘a一直按下第一个立刻输出顿了一下才一直输出。
*/
// 事件类别-一个类一个标识
enum class EventType{None  0,WindowClose, WindowResize, WindowFocus, WindowLostFocus, WindowMoved,AppTick, AppUpdate, AppRender,KeyPressed, KeyReleased,MouseButtonPressed, MouseButtonReleased, MouseMoved, MouseScrolled
};
// 事件分类-多个类一个分类即多个类属于同一个分类
enum EventCategory
{None  0,EventCategoryApplication	 BIT(0),	// 1EventCategoryInput			 BIT(1),	// 2EventCategoryKeyboard		 BIT(2),	// 4EventCategoryMouse			 BIT(3),	// 8EventCategoryMouseButton	 BIT(4)	// 16
};
// 宏定义每个子类都需要重写父类虚函数代码可以用宏定义简洁代码
#define EVENT_CLASS_TYPE(type) static EventType GetStaticType() { return EventType::##type; }\virtual EventType GetEventType() const override { return GetStaticType(); }\virtual const char* GetName() const override { return #type; }#define EVENT_CLASS_CATEGORY(category) virtual int GetCategoryFlags() const override { return category; }class HAZEL_API Event
{friend class EventDispatcher;public:virtual EventType GetEventType() const  0;		// 获取本事件是哪个类型virtual const char* GetName() const  0;		// 获取本事件的名称c字符数组virtual int GetCategoryFlags() const  0;		// 获取本事件属于哪个分类virtual std::string ToString() const { return GetName(); }	// 获取本事件的名称从c字符数组转为字符串inline bool IsInCategory(EventCategory category){return GetCategoryFlags()  category;}protected:bool m_Handled  false;
};WindowResizeEvent class HAZEL_API WindowResizeEvent : public Event
{public:WindowResizeEvent(unsigned int width, unsigned int height): m_Width(width), m_Height(height) {}inline unsigned int GetWidth() const { return m_Width; }inline unsigned int GetHeight() const { return m_Height; }std::string ToString() const override{std::stringstream ss;ss  WindowResizeEvent:   m_Width  ,   m_Height;return ss.str();}// 关键地方用宏定义来重写虚函数EVENT_CLASS_TYPE(WindowResize)EVENT_CLASS_CATEGORY(EventCategoryApplication)private:unsigned int m_Width, m_Height;
};关键地方用宏定义来重写虚函数 // 宏定义每个子类都需要重写父类虚函数代码可以用宏定义简洁代码
#define EVENT_CLASS_TYPE(type) static EventType GetStaticType() { return EventType::##type; }\virtual EventType GetEventType() const override { return GetStaticType(); }\virtual const char* GetName() const override { return #type; }EVENT_CLASS_TYPE(WindowResize)
EVENT_CLASS_CATEGORY(EventCategoryApplication)
// 会编译成
static EventType GetStaticType() { return EventType::WindowResize; } virtual EventType GetEventType() const override { return GetStaticType(); } virtual const char* GetName() const override { return WindowResize; }
virtual int GetCategoryFlags() const override { return EventCategoryApplication; }可见##type是保持为变量#type是转换为字符串  
包含头文件 premake的lua脚本中 includedirs
{%{prj.name}/src,%{prj.name}/vendor/spdlog/include
}所以Hazel项目的包含目录包含src目录 // 因为Event.h所在src/Hazel/Events/Event.h
// 其它类包含Event.h可以写成
#include Hazel/Events/Event.h// 而不用前缀src重新编译  
使用事件 application.h #include Core.h
#include Events/Event.h// 包含事件基类namespace Hazel {Application.cpp #include Application.h
#include Hazel/Events/ApplicationEvent.h // 包含具体事件
#include Hazel/Log.hnamespace Hazel {Application::Application(){}Application::~Application(){}void Application::Run(){WindowResizeEvent e(1280, 720);	// 使用自定义事件if (e.IsInCategory(EventCategoryApplication))	// 判断是否对应的分类{HZ_TRACE(e);	// 输出事件}if (e.IsInCategory(EventCategoryInput)){HZ_TRACE(e);}while (true);}
}效果   
事件调度器代码 
// 事件调度器类
class EventDispatcher
{templatetypename Tusing EventFn  std::functionbool(T);	// 声明function接受返回类型bool参数是T的函数public:EventDispatcher(Event event): m_Event(event){}templatetypename Tbool Dispatch(EventFnT func)				// function参数接收函数指针{if (m_Event.GetEventType()  T::GetStaticType())	// 拦截的事件和想处理的事件类型是否匹配{m_Event.m_Handled  func(*(T*)m_Event);		// 处理拦截的事件return true;}return false;}private:Event m_Event;								// 拦截的事件
};这个类的本身与作用由于function模板变得很难看懂可以看结合开头的事件设计图和后面的function基本使用代码一步一步理解 
C知识Function 
Bind用法 
#include iostream
#include functional
using namespace std;
using namespace std::placeholders;// 占位符空间
void f(int a, int b, int c, int d, int e)
{cout  a     b     c     d     e  endl;
}
// _1 是在命名空间里的bind可以翻转参数位置
int main(){int a  1, b  2, c  3;auto g  bind(f, a, b, c, _2, _1);g(4, 5);	// 1 2 3 5 4return 0;
}说明 bind可以用_1,_2预占位g可以理解是functionvoid(int a, int b, int c, int d, int e);function对象auto g  bind(f, a, b, c, _2, _1);将f函数绑定到function对象g上并定好第一、二、三个参数g(4, 5)将调用执行f函数4将绑定到_1上5将绑定到_2上本来_1实参会赋给f函数的d形参_2实参给e形参但由于bind时改变了对应位置于是_1给e_2给d输出 1 2 3 5 4  
function基本使用 
#include iostream
#include string
#include functional
using namespace std;
using namespace std::placeholders;// 占位符空间// 事件类与函数定义
class Event {							// 事件基类
public:virtual void Say() { cout  Event::Say()  endl; }bool m_Handled;						// 事件是否处理完
};
class WindowCloseEvent : public Event {	// 窗口关闭事件子类
public:virtual void Say() { cout  WindowEvent::Say()  endl;}
};
void LayerOnEvent(Event e) {e.Say();cout  LayerOnEvent(Event e)  endl;
}// 4.using带泛型的function
templatetypename T
using TemplateEventFn  std::functionvoid(T);// 5.额外理解宏定义
#define BIND_EVENT_FN(x) bind(x, _1)int main() {// 1.普通的functionEvent e1;functionvoid(Event) func1  LayerOnEvent;// 绑定返回类型void参数是Event的函数func1(e1);// 2.使用using 代替functionusing EventFn  std::functionvoid(Event);EventFn func2  LayerOnEvent;func2(e1);// 3.使用bindfunctionvoid(Event) func3_1  bind(LayerOnEvent, _1);func3_1(e1);EventFn func3_2  bind(LayerOnEvent, _1);// bind第一个参数函数地址第二个参数是调用Print函数时的参数func3_2(e1);// 4.使用template的 functionTemplateEventFnEvent func4  LayerOnEvent;func4(e1);func4  bind(LayerOnEvent, _1);func4(e1);// 5.额外理解宏定义TemplateEventFnEvent func5  BIND_EVENT_FN(LayerOnEvent);func5(e1);// 6.额外理解。尝试引用类型是否能执行子类的虚函数functionvoid(Event) func6  LayerOnEvent;WindowCloseEvent windowe1;Event event1  windowe1;func6(event1);	/*WindowEvent::Say()LayerOnEvent(Event e)*/return 0;
}012、事件系统-Demo 声明 由于008节设计了事件系统而009只是实现了自定义事件占整个事件系统的很小部分 于是我把012窗口事件的内容简化成demo符合一开始的计划事件图。 demo是分为一个小点一个小点的更好来理解整个事件系统。  
Layer用EventDispacher拦截处理事件56难理解 前言 此点Demo代码是对应一开始计划事件系统类图的第5、6步而其它步骤的代码是模拟并且略过   代码 阅读代码请按照注释的1、2、3、4、5、5.1…顺序阅读 #include iostream
#include string
#include functional
using namespace std;
using namespace std::placeholders;// 占位符空间// 事件类定义//
class Event {							// 事件基类
public:virtual void Say() { cout  Event::Say()  endl; }bool m_Handled;						// 事件是否处理完
};
class WindowCloseEvent : public Event {	// 窗口关闭事件子类
public:virtual void Say() { cout  WindowEvent::Say()  endl; }
};// 事件调度器//
class EventDispatcher {
public:EventDispatcher(Event event) :m_Event(event) {}templatetypename Tusing TemplateEventFn  std::functionbool(T);	// 使用using模板function// 5.2 using TemplateEventFn  functionvoid(WindowCloseEvent) 与 TemplateEventFnWindowCloseEvent functemplatetypename Tvoid Dispatch(TemplateEventFnT func) {			// 此时func  Layer::OnWindowClose// 5.3 拦截的事件m_Event与layer层想处理的事件类型是否匹配if (true) {										// 假设匹配cout  EventDispatcher::Dispatch(TemplateEventFnT func)  endl;// 6 执行layer的OnWindowClose处理拦截的m_Event事件m_Event.m_Handled  func(*(T*)m_Event);/*	(0)	函数声明OnWindowClose(WindowEvent e);(0) 显式调用OnWindowClose(*(WindowEvent*)m_Event)	(1) OnWindowClose参数要求WindowEvent而m_Event是Event类型所以要(WindowEvent*)m_Event(2) OnWindowClose参数是引用类型所以要*(WindowEvent*)m_Event*/}}
private:Event m_Event;										// 拦截的事件
};
// Layer层//
class Layer {											// 属于Application的layer层
public:// 5.每个Layer层的OnEvent用事件调度器拦截自己层想要拦截的事件并且处理void OnEvent(Event e) {EventDispatcher dispatcher(e);// 5.1拦截WindowCloseEvent事件并用本类的OnWindowClose函数处理dispatcher.DispatchWindowCloseEvent(bind(Layer::OnWindowClose, this, _1));// bind在上一小点有demothis在类时要使用_1依旧是执行OnWindowClose的参数}bool OnWindowClose(WindowCloseEvent e) {e.Say();cout  Layer::OnWindowClose(WindowCloseEvent e)  endl;return true;									// 代表处理完了}
};int main() {// 1.Application对象创建窗口类窗口类初始化了glfw窗口// 2.将glfw窗口事件封装成自己系统的事件WindowCloseEvent windowe1;				// 3.回调Application的OnEvent函数并将事件作为其OnEvent的参数// 4.Application的OnEvent将事件传递给Application的所有Layer层的OnEventLayer layer;layer.OnEvent(windowe1);return 0;
}效果   
Application设置window回调函数与回调123 前言 此点是对应一开始计划事件系统类图的第1、2、3步但没有glfw窗口只能模拟glfw窗口事件   代码 #include iostream
#include string
#include functional
using namespace std;
using namespace std::placeholders;// 占位符空间// 事件类定义//
class Event {							// 事件基类
public:virtual void Say() { cout  Event::Say()  endl; }bool m_Handled;						// 事件是否处理完
};
class WindowCloseEvent : public Event {	// 窗口关闭事件子类
public:virtual void Say() { cout  WindowEvent::Say()  endl;}
};// 窗口类定义//
class Window {
public:using EventCallbackFn  std::functionvoid(Event);	// 声明function类型void function(Event)static Window* CreateWindow() {							// 模拟创建窗口return new Window;}void SetEventCallback(const EventCallbackFn callback) {EventCallback  callback;							// 绑定Application::OnEvent}void SendEvent() {cout  Window::模拟glfw窗口事件  endl;// 2.将glfw窗口事件封装成自己系统的事件WindowCloseEvent windowe;// 3.回调Application的OnEvent函数并将事件作为其OnEvent的参数EventCallback(windowe);}EventCallbackFn EventCallback;							// 定义function
};// 应用层类定义//
class Application {
public:Window* win;											// 持有的窗口类void OnEvent(Event event) {event.Say();cout  Application::OnEvent(Event event)  endl;// 4.Application的OnEvent将事件传递给Application的所有Layer层的OnEvent// ......}
};
int main() {Application app;// 1.1Application对象创建窗口类窗口类初始化了glfw窗口app.win  Window::CreateWindow();// 1.2Application设置窗口事件的回调函数app.win-SetEventCallback(bind(Application::OnEvent, app, _1));// bind的argument1是函数地址arug2是哪个类arug3是调用OnEvent的参数// 1.3模拟glfw窗口事件app.win-SendEvent();return 0;
}效果   
Application将事件传给Layer4与整个事件系统流程 前言 此点是对应一开始计划事件系统类图的第4步并且整合前两点的代码除了缺少glfw窗口与glfw窗口事件是完整的事件系统流程   代码 #include iostream
#include string
#include functional
using namespace std;
using namespace std::placeholders;// 占位符空间// 事件类定义//
class Event {							// 事件基类
public:virtual void Say() { cout  Event::Say()  endl; }bool m_Handled;						// 事件是否处理完
};
class WindowCloseEvent : public Event {	// 窗口事件子类
public:virtual void Say() { cout  WindowEvent::Say()  endl;}
};
// 事件调度器//
class EventDispatcher {
public:EventDispatcher(Event event) :m_Event(event) {}templatetypename Tusing TemplateEventFn  std::functionbool(T);	// 使用using模板function// 5.2 using TemplateEventFn  functionvoid(WindowCloseEvent) 与 TemplateEventFnWindowCloseEvent functemplatetypename Tvoid Dispatch(TemplateEventFnT func) {			// 此时func  Layer::OnWindowClose// 5.3 拦截的事件m_Event与layer层想处理的事件类型是否匹配if (true) {										// 假设匹配cout  EventDispatcher::Dispatch(TemplateEventFnT func)  endl;// 6 执行layer的OnWindowClose处理拦截的m_Event事件m_Event.m_Handled  func(*(T*)m_Event);/*(0)	函数声明OnWindowClose(WindowEvent e);(0) 显式调用OnWindowClose(*(WindowEvent*)m_Event)(1) OnWindowClose参数要求WindowEvent而m_Event是Event类型所以要(WindowEvent*)m_Event(2) OnWindowClose参数是引用类型所以要*(WindowEvent*)m_Event*/}}
private:Event m_Event;										// 拦截的事件
};
// Layer层//
class Layer {											// 属于Application的layer层
public:// 5.每个Layer层的OnEvent用事件调度器拦截自己层想要拦截的事件并且处理void OnEvent(Event e) {EventDispatcher dispatcher(e);// 5.1拦截WindowCloseEvent事件并用本类的OnWindowClose函数处理dispatcher.DispatchWindowCloseEvent(bind(Layer::OnWindowClose, this, _1));// bind在上一小点有demothis在类时要使用_1依旧是执行OnWindowClose的参数}bool OnWindowClose(WindowCloseEvent e) {e.Say();cout  Layer::OnWindowClose(WindowCloseEvent e)  endl;return true;									// 代表处理完了}
};
// 窗口类定义//
class Window {
public:using EventCallbackFn  std::functionvoid(Event);	// 声明function类型void function(Event)static Window* CreateWindow() {							// 模拟创建窗口return new Window;}void SetEventCallback(const EventCallbackFn callback) {EventCallback  callback;							// 绑定Application::OnEvent}void SendEvent() {cout  Window::模拟glfw窗口事件  endl;// 2.将glfw窗口事件封装成自己系统的事件WindowCloseEvent windowe;// 3.回调Application的OnEvent函数并将事件作为其OnEvent的参数EventCallback(windowe);}EventCallbackFn EventCallback;							// 定义function
};// 应用层类定义//
class Application {
public:Window* win;											// 持有的窗口类void OnEvent(Event event) {cout  Application::OnEvent(Event event)  endl;// 4.Application的OnEvent将事件传递给Application的所有Layer层的OnEventLayer layer;layer.OnEvent(event);}
};
int main() {Application app;// 1.1Application对象创建窗口类窗口类初始化了glfw窗口app.win  Window::CreateWindow();// 1.2Application设置窗口事件的回调函数app.win-SetEventCallback(bind(Application::OnEvent, app, _1));// bind的argument1是函数地址arug2是哪个类arug3是调用OnEvent的参数// 1.3模拟glfw窗口事件app.win-SendEvent();return 0;
}效果