一种方法是为窗口的每个子窗口的鼠标按下事件注册一个事件处理程序。这样,如果满足某些条件(例如按住Alt键并单击),窗口就可以控制鼠标。
其中一些内容在wxWidgets\samples\shaped\shaped.cpp示例中有所说明,但基本上您需要执行以下操作:
在窗口中添加一个方法,在所有子窗口都已添加后调用该方法。
void MyFrame::BindChildEvents()
{
visit_recursively(this,
[] (wxWindow *window, MyFrame *thiz) {
// Bind all but the main window's event
if(window != thiz)
{
window->Bind(wxEVT_LEFT_DOWN, &MyFrame::OnChildLeftDown, thiz);
}
},
this
);
}
你可以自己编写窗口树遍历的代码,但我在这里使用了这个小辅助函数:
template<typename F, typename... Args>
void
visit_recursively(wxWindow *window, F func, Args&&... args)
{
for(auto&& child : window->GetChildren())
{
visit_recursively(child, func, std::forward<Args>(args)...);
}
func(window, std::forward<Args>(args)...);
}
然后您设置鼠标按下事件拦截处理程序:
void MyFrame::OnChildLeftDown(wxMouseEvent& event)
{
if(event.GetModifiers() == wxMOD_ALT)
{
CaptureMouse();
const auto eventSource = static_cast<wxWindow *>(event.GetEventObject());
const auto screenPosClicked = eventSource->ClientToScreen(event.GetPosition());
const auto origin = GetPosition();
mouseDownPos_ = screenPosClicked - origin;
}
else
{
event.Skip();
}
}
您可以通过随着鼠标移动窗口来处理鼠标移动:
void MyFrame::OnMouseMove(wxMouseEvent& event)
{
if(event.Dragging() && event.LeftIsDown())
{
const auto screenPosCurrent = ClientToScreen(event.GetPosition());
Move(screenPosCurrent - mouseDownPos_);
}
}
在 wxEVT_LEFT_UP
和 wxEVT_MOUSE_CAPTURE_LOST
事件中一定要调用 ReleaseMouse()
。