wxWidgets - Creating a borderless frame movable

2.3k views Asked by At

I am attempting to convert one of my application written in C# - Windows Forms to C++ - wxWidgets.

My app is borderless and has a thin, transparent panel on top of the form which can be used to move the form. (I used the technique from this question: Make a borderless form movable?)

Now, I basically want to do the same thing in wxWidgets, I've searched around the internet on how to handle a mouse down event over a wxPanel and found a couple examples but both used wxPython in their article/question and I have no knowledge about Python at all.

So how to do the same thing in C++ - wxWidgets?

2

There are 2 answers

0
ravenspoint On

"how to fire a mouse down event?". You do not need to worry about 'firing' the event - the OS does that. You need to handle the event which is EVT_LEFT_DOWN. Is your question about how to handle wxWidgets events? Have you looked at the sample programs? http://docs.wxwidgets.org/2.6/wx_samples.html They are all in C++.

There is a description of how to handle events here: http://docs.wxwidgets.org/2.6/wx_eventhandlingoverview.html#eventhandlingoverview

If you question is about something more specific in the details of handling the EVT_LEFT_DOWN event, then please post your code, describe what you want it to do and what it does instead.

0
AudioBubble On

One way is for the window to register an event handler for each of its child windows' mouse down events. That way the window can take control of the mouse if a certain condition is met (e.g. the Alt key is held down while clicking).

Some of this stuff is illustrated in the wxwidgets\samples\shaped\shaped.cpp sample but basically you do this:

Add a method to your window that you call after all the child windows have been added:

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
    );
}

You can roll your own window tree traversal but I use this little helper function here:

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)...);
}

Then you set up your mouse down event interception handler:

void MyFrame::OnChildLeftDown(wxMouseEvent& event)
{
    // If Alt is pressed while clicking the child window start dragging the window
    if(event.GetModifiers() == wxMOD_ALT)
    {
        // Capture the mouse, i.e. redirect mouse events to the MyFrame instead of the
        // child that was clicked.
        CaptureMouse();

        const auto eventSource = static_cast<wxWindow *>(event.GetEventObject());
        const auto screenPosClicked = eventSource->ClientToScreen(event.GetPosition());
        const auto origin = GetPosition();

        mouseDownPos_ = screenPosClicked - origin;
    }
    else
    {
        // Do nothing, i.e. pass the event on to the child window
        event.Skip();
    }
}

And you handle mouse motion by moving the window along with the mouse:

void MyFrame::OnMouseMove(wxMouseEvent& event)
{
    if(event.Dragging() && event.LeftIsDown())
    {
        const auto screenPosCurrent = ClientToScreen(event.GetPosition());
        Move(screenPosCurrent - mouseDownPos_);
    }
}

Be sure to call ReleaseMouse() in the wxEVT_LEFT_UP and wxEVT_MOUSE_CAPTURE_LOST events.