Page 1 of 1

wxEVT_LEFT_DOWN on menuBar

Posted: Wed Jul 03, 2019 2:49 am
by mxoliveira73
wxEVT_LEFT_DOWN doesn't work over a wxMenuBar?

Code: Select all

OnLeftDown(wxMouseEvent& event);

wxmenuBar* menuBar = new wxMenuBar();

menuBar->Bind(wxEVT_LEFT_DOWN,&MyFrame::OnLeftDown,this);

void MyFrame::OnLeftDown(wxMouseEvent& event)
{
// do something here
}

Re: wxEVT_LEFT_DOWN on menuBar

Posted: Wed Jul 03, 2019 5:43 am
by evstevemd
what do you want to accomplish?

Re: wxEVT_LEFT_DOWN on menuBar

Posted: Wed Jul 03, 2019 8:24 am
by Deluge
I think this is because of wxMenuBar's implicit handling of mouse events. I'm not sure how you would override it.

Tested it out with this code:

Code: Select all

#include <iostream>
#include <wx/wx.h>

using namespace std;


class MyFrame : public wxFrame {
public:
	MyFrame();
private:
	void OnLeftDown(wxMouseEvent& event);
} *frame;

MyFrame::MyFrame() :
		wxFrame(NULL, wxID_ANY, _T("Testing Mouse Event")) {
	wxMenuBar* menuBar = new wxMenuBar();
	menuBar->Append(new wxMenu(), _T("File"));

	SetMenuBar(menuBar);

	// bind to wxMenuBar
	menuBar->Bind(wxEVT_LEFT_DOWN, &MyFrame::OnLeftDown, this);
	// bind to wxFrame
	Bind(wxEVT_LEFT_DOWN, &MyFrame::OnLeftDown, this);

	// test OnLeftDown method at initialization
	wxPostEvent(menuBar, wxMouseEvent(wxEVT_LEFT_DOWN));
}

void MyFrame::OnLeftDown(wxMouseEvent& event) {
	cout << "Left mouse down event\n";
}


class MyApp : public wxApp {
public:
	virtual bool OnInit();
} *app;

bool MyApp::OnInit() {
	frame = new MyFrame();
	SetTopWindow(frame);
	frame->Show(true);

	return true;
}


int main(int argc, char** argv) {
	cout << "Starting test ...\n";

	app = new MyApp();
	wxApp::SetInstance(app);
	wxEntry(argc, argv);

	return 0;
}
Binding to the wxFrame works, but not binding to the menu bar.

--- Edit ---

Might be able to make your own custom menu bar class derived from wxMenu bar & call Unbind or Disconnect in the constructor. But, not sure if that will work.

Re: wxEVT_LEFT_DOWN on menuBar

Posted: Wed Jul 03, 2019 4:15 pm
by mxoliveira73
Responding to evstevemd

ask: what do you want to accomplish?

R: Drag the menuBar and togheter the Frame.
Create app whitout Title Bar; then, to move the frame in the screen, drag the menuBar whit the cursor mouse. Togheter drag Frame.

It's possible, if the menuBar react to the Evt_LEFT_DOWN. But, it seems not possible.

The right question is:

Is it possible the menuBar react to the EVT_LEFT_DOWN mouse event?

Re: wxEVT_LEFT_DOWN on menuBar

Posted: Wed Jul 03, 2019 4:56 pm
by doublemax
Is it possible the menuBar react to the EVT_LEFT_DOWN mouse event?
There is not much you can do wrong here, and i tested it myself. Apparently the answer is no, at least under Windows. I didn't test on other platforms.

If you really need this i would try without a menubar and use a toolbar to mimic the functionality of the menubar. Of course it won't look exactly the same.

Or you could use the empty spots in the main window for dragging. It depends on the type of application and potential user base if that's a realistic solution.

Re: wxEVT_LEFT_DOWN on menuBar

Posted: Wed Jul 03, 2019 6:00 pm
by PB
I would say that at least on MSW, it probably cannot work.

While wxMenuBar is in wxWidgets derived from wxWindow, the native menu is not a window (it does not have a HWND, it is a HMENU). The menubar there is considered part of the non-client area and DefWindowProc returns HTMENU in response to WM_NCHITTEST where the coordinates match the menubar.

I mashed up this UNTESTED example (without error handling) how to drag a window by the "empty" area of a frame's menubar on MSW. The code pretends that the area of the menubar not taken up by menus (minus some gap) is the window caption. No idea whether this is a proper solution, just one that came to my mind as easy and seemingly working. The code for computing the menubar area does not account for the situation where menubar overflows to more than one row, but that should be easy to handle. However, the code may have some serious problems I am not aware of, who knows - probably not suitable for production.

Anyway, in the test app one can grab the menubar (after about 30 pixels after the last item) and drag the window around.

Code: Select all

#include <wx/wx.h>

class MyFrame : public wxFrame
{
public:
    MyFrame() : wxFrame(NULL, wxID_ANY, _("Test"), wxDefaultPosition, wxSize(800, 600))
    {
        wxMenu* fileMenu = new wxMenu;
        fileMenu->Append(wxID_OPEN);
        fileMenu->Append(wxID_SAVE);

        wxMenu* editMenu = new wxMenu;
        editMenu->Append(wxID_CUT);
        editMenu->Append(wxID_COPY);

        wxMenuBar* menuBar = new wxMenuBar();
        menuBar->Append(fileMenu, _("&File"));
        menuBar->Append(editMenu, _("&Edit"));
        SetMenuBar(menuBar);

        wxTextCtrl* logCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
            wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
        wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));
    }

#ifdef __WXMSW__ 
    WXLRESULT MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) override
    {
        WXLRESULT result = wxFrame::MSWWindowProc(nMsg, wParam, lParam);

        if ( nMsg == WM_NCHITTEST && result == HTMENU && GetMenuBar() )
        {
            size_t menuCount = GetMenuBar()->GetMenuCount();

            if ( menuCount )
            {
                static const LONG gap = 30; // between last menu item and draggable area
                
                RECT menuItemRect{0};
                POINT mousePos{0};

                ::GetMenuItemRect(GetHandle(), GetMenuBar()->GetHMenu(), menuCount - 1, &menuItemRect);
                ::MapWindowPoints(nullptr, GetHandle(), (LPPOINT)&menuItemRect, 2);

                mousePos.x = LOWORD(lParam);
                mousePos.y = HIWORD(lParam);
                ::ScreenToClient(GetHandle(), &mousePos);

                if ( mousePos.x > menuItemRect.right + gap )
                {
                    wxLogMessage("Pretending this part of menubar is caption.");
                    result = HTCAPTION;
                }
            }            
        }

        return result;
    }
#endif // #ifdef __WXMSW__
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        (new MyFrame)->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
EDIT I forgot to add that I consider this approach user unfriendly. Unlike other modifications of the NC area in applications such as those using ribbon or web browsers, you would not have any window caption nor the min, max/restore, and close buttons.

Re: wxEVT_LEFT_DOWN on menuBar

Posted: Thu Jul 04, 2019 1:51 am
by mxoliveira73
Amazing. It works fine in MS Windows the code of PB. Big big thanks, PB, evstevemd, deluge, doublemax... I'm almost finishing my app. Would be impossible whitout the help of you.... Really, this point it's level so high to me, only a bigginner. I'm styuding the code to underst it... thanks a lot... It's had been a good experience to me this fórum and WxWidgets... It's very quicly in aplication...

Re: wxEVT_LEFT_DOWN on menuBar

Posted: Thu Jul 04, 2019 7:30 am
by evstevemd
Welcome to wxWidgets community. Keep going =D>

Re: wxEVT_LEFT_DOWN on menuBar

Posted: Fri Jul 05, 2019 2:20 pm
by ONEEYEMAN
Hi,
On top of what PB said - this solutio is very hackish and un-portable.
Frame title bar's are exist for a reason - not just to show the application name and some other info but in order to be able to drag the window around.

You should re-consider you design and add the menu to "Exit fullscreen mode" to make the window as "normal".

Thank you.