视频学到了S022 ,分析一下Hazel的事件系统是如何实现的。
先看看Application类里如何处理jj下面这里的 变量层栈的for循环里,if(e.Handled)为true,就退出不处理了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void Application::OnEvent (Event& e) { HZ_PROFILE_FUNCTION (); EventDispatcher dispatcher (e) ; dispatcher.Dispatch <WindowCloseEvent>(HZ_BIND_EVENT_FN (Application::OnWindowClose)); dispatcher.Dispatch <WindowResizeEvent>(HZ_BIND_EVENT_FN (Application::OnWindowResize)); for (auto it = m_LayerStack.rbegin (); it != m_LayerStack.rend (); ++it) { if (e.Handled) break ; (*it)->OnEvent (e); } }
这里显示用了一个dispatcher来处理窗口关闭和窗口重定义大小,这里的写法是判断事件类型是否符合传入的Callback处理函数,如果匹配了,就设置Handled为true(看下面的OnWindowClose返回的true,这样异或为true)。看下面的循环,Handled为true会直接退出。
dispatch 1 2 3 4 5 6 7 8 9 10 11 template <typename T, typename F>bool Dispatch (const F& func) { if (m_Event.GetEventType () == T::GetStaticType ()) { m_Event.Handled |= func (static_cast <T&>(m_Event)); return true ; } return false ; }
1 2 3 4 5 6 7 8 9 bool Application::OnWindowClose (WindowCloseEvent& e) { m_Running = false ; return true ; }
下面这个事件处理返回的就是false,表示这个事件没有处理完,穿透层,下一层继续处理。
1 2 3 4 5 6 bool ImGuiLayer::OnMouseButtonPressedEvent (MouseButtonPressedEvent& e) { ImGuiIO& io = ImGui::GetIO (); io.MouseDown[e.GetMouseButton ()] = true ; ET_CORE_TRACE (e.ToString ()); return false ; }
这个Handled可以在层设置阻挡,ImGuiLayer这里的设置: 阻挡成功Handled就设置为true。
1 2 3 4 5 6 7 8 9 void ImGuiLayer::OnEvent (Event& e) { if (m_BlockEvents) { ImGuiIO& io = ImGui::GetIO (); e.Handled |= e.IsInCategory (EventCategoryMouse) & io.WantCaptureMouse; e.Handled |= e.IsInCategory (EventCategoryKeyboard) & io.WantCaptureKeyboard; } }
那么如何设置事件类型呢? 在事件发生的时候,glfw会自动调用下面我们在窗口初始化的时候设置的回调函数,这里的data.EventCallback(evnet)就是设置Event的类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 glfwSetWindowSizeCallback (m_Window, [](GLFWwindow* window, int width, int height) { WindowData& data = *(WindowData*)glfwGetWindowUserPointer (window); data.Width = width; data.Height = height; WindowResizeEvent event (width, height); data.EventCallback (event); });
data的类型就是下面的函数指针
1 using EventCallbackFn = std::function<void (Event&)>;
这里提供了Event类型,EventDispatcher提供了处理事件的函数。 这就是我对整个事件系统的理解了。