Page 1 of 1

How write own widget?

Posted: Wed Sep 09, 2020 9:17 pm
by AndrzejB
Is any simple example? I suppose, most of wx widgets uses GTK but some are drawed. I want draw my widget : breadcrumb.

Re: How write own widget?

Posted: Wed Sep 09, 2020 10:28 pm
by ONEEYEMAN
Hi,
With wxWidgets, most controls are uses the platform-native implementation, so that on the specific platform the application will look native.

However, not all platforms support all controls and some controls does not have a native implementation at all (like wxGrid - as you mentioned).

Basically to create you own control:
1. You create your own class based on the wxWindow or wxPanel.
2. You handle the EVT_PAINT.
3. In the handler you create the wxPainDC (even if you will not use it).
4. You do you drawing in that handler.
5. You add any additional logic your control require - mouse click, keyboard processing.
6. You will also need to override the GetBestSize() function in order to size the control correctly.

That pretty much sums it up.

Unless you have a control that is based on the existig control...

Thank you.

Re: How write own widget?

Posted: Thu Sep 10, 2020 5:16 am
by doublemax
You can use this as a starting point:
https://wiki.wxwidgets.org/Painting_your_custom_control

Re: How write own widget?

Posted: Thu Sep 10, 2020 6:16 am
by AndrzejB
"Derive from wxWindow for simple (i.e. not containing children) controls, not from wxControl, which is the base class for the native controls."
If we want child controls (for example drawe listbox with child scrollbars) need derive from wxControl?
I use childs (wxButton) with wxWindow and is ok.
My control will contain wxMenu and wxButton. I want draw arrows on button. Is possible draw on button icon or better draw arrow on wxButton canvas?
My whole component has small button, and method render, in this method I can get dc of small button or is better way?

Code: Select all

void wxCustomButton::render(wxDC&  dc)
{
   *wxClientDC dc1(smallButton);
   ..
 }

Re: How write own widget?

Posted: Thu Sep 10, 2020 11:50 am
by AndrzejB
Button can have bitmap, but always has (size=5) border:

Code: Select all

    wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
    arrowButton = new wxButton(this, 0, wxT(""), wxPoint(10,10), wxSize(140,20));
    wxBitmap bitmap(arrowButton->GetClientRect().GetWidth(), arrowButton->GetClientRect().GetHeight());
    wxMemoryDC memdc;
    memdc.SelectObject(bitmap);
    memdc.SetBrush( *wxRED_BRUSH );
    memdc.DrawRectangle(0,0, bitmap.GetWidth(), bitmap.GetHeight());
     arrowButton->SetBitmap(bitmap);
    sizer->Add(arrowButton, 0, wxALL, 0);
    SetSizer(sizer);
is possibe draw on bitmap which is whole button?--> my own button class

My control has two childs: button and menu.
If I define BEGIN_EVENT_TABLE for frame - it catch commands like EVT_MENU but BEGIN_EVENT_TABLE for control has only mouse, and keyboard events but not commands from childs. How catch commands like child button is clicked?

Re: How write own widget?

Posted: Thu Sep 10, 2020 4:08 pm
by ONEEYEMAN
Hi,
When you working with the custom control you want to catch low-level events, not the high level ones. Therefore you should operate with the left/right/middle mouse button down/up, keyboard keypress (EVT_CHAR_HOOK/EVT_KEY_DOWN/EVT_KEY_UP).

If you base you control on the existing widget, you can catch any command event you want but then you will have to handle it inside you control.

And so when you want to catch the event you should define the event table inside you own control - don't do it inside frame.

Thank you.

Re: How write own widget?

Posted: Thu Sep 10, 2020 4:37 pm
by doublemax
If we want child controls (for example drawe listbox with child scrollbars) need derive from wxControl?
Use wxPanel in this case.
My control will contain wxMenu and wxButton. I want draw arrows on button. Is possible draw on button icon or better draw arrow on wxButton canvas?
You can't draw on top of native controls to change their look. You might have to use a custom control that is 100% custom drawn. You could use wxRendererNative to draw a button into your wxDC and then draw on top of it. https://docs.wxwidgets.org/trunk/classw ... ative.html
If I define BEGIN_EVENT_TABLE for frame - it catch commands like EVT_MENU but BEGIN_EVENT_TABLE for control has only mouse, and keyboard events but not commands from childs. How catch commands like child button is clicked?
All events that derive from wxCommandEvent will automatically travel up to the parent (and grandparent and so on) if you don't handle the event in your control. If you handle it, call event.Skip() in the event handler, so that processing continues.

Re: How write own widget?

Posted: Fri Sep 11, 2020 7:51 am
by AndrzejB
I derived from wxPanel
I write

Code: Select all

BEGIN_EVENT_TABLE(wxxBreadCrumb, wxPanel)
                EVT_MENU(wxID_OPEN, wxxBreadCrumb::clicked)
but is error: : invalid static_cast from type ‘void (wxxBreadCrumb::*)(wxMouseEvent&)’ to type ‘wxCommandEventFunction’ {aka ‘void (wxEvtHandler::*)(wxCommandEvent&)’}
4 | EVT_MENU(wxID_HIGHEST+1, wxxBreadCrumb::onMenu)

My compiler says:
Replacement:
wxEventTableEntry(wxEVT_MENU, wxID_OPEN, wxID_ANY, wxNewEventTableFunctor(wxEVT_MENU, wxEventFunctionCast(
static_cast<wxCommandEventFunction>(&wxxBreadCrumb::clicked))), __null),
Header Search Paths

How use it with macro?

Re: How write own widget?

Posted: Fri Sep 11, 2020 7:56 am
by ONEEYEMAN
Hi,
EVT_MENU is a wxCommandEvent - check the documentation when in doubt.

So the signature should be:

Code: Select all

void wxxBreadCrumb::clicked(wxCommandEvent &event)
Thank you.

Re: How write own widget?

Posted: Fri Sep 11, 2020 8:28 am
by doublemax
BTW: As your custom control is a wxPanel (or wxWindow), how can it generate menu events? Usually only wxFrames can do that. Or are these coming from a popup menu?

Re: How write own widget?

Posted: Fri Sep 11, 2020 9:46 am
by AndrzejB
Aaah, I search error in other place.
My custom button will emit event on press (mousedown), noy click (mouse up) event.
How distingush wxEVT_BUTTON event between press and click?

Re: How write own widget?

Posted: Fri Sep 11, 2020 10:44 am
by doublemax
AndrzejB wrote:
Fri Sep 11, 2020 9:46 am
Aaah, I search error in other place.
My custom button will emit event on press (mousedown), noy click (mouse up) event.
How distingush wxEVT_BUTTON event between press and click?
If you want a custom button that triggers on mouse down (instead of the usual mouse up), you need to:

a) catch the mouse down event and generate your own wxEVT_BUTTON event
b) catch the "normal" wxEVT_BUTTON event that the button would usually emit and consume it

Code: Select all

class MyButton : public wxButton
{
public:
  MyButton( wxWindow *parent, wxWindowID id, const wxString &label=wxEmptyString, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=0, const wxValidator &validator=wxDefaultValidator, const wxString &name=wxButtonNameStr)
    :wxButton( parent, id, label, pos, size, style, validator, name)
  {
    Bind(wxEVT_LEFT_DOWN, &MyButton::OnLeftDown, this);
    Bind(wxEVT_BUTTON, &MyButton::OnButton, this);
  };

  void OnLeftDown(wxMouseEvent &event) {
    wxLogDebug("OnLeftDown");
    wxCommandEvent newEvent( wxEVT_BUTTON, GetId() );
    newEvent.SetEventObject(this);
    GetParent()->GetEventHandler()->ProcessEvent(newEvent);
  }
  
  void OnButton(wxCommandEvent &event) {
    wxLogDebug("OnButton");
    // do nothing, just consume the event so that it's not passed to the parent
  }
};
Edit: It turns out that (at least under Windows), catching and consuming the wxEVT_BUTTON event is not necessary, as handling wxEVT_LEFT_DOWN already seems to take care of that. But it doesn't hurt either, so i left it in.