How write own widget?

Are you writing your own components and need help with how to set them up or have questions about the components you are deriving from ? Ask them here.
Post Reply
AndrzejB
Experienced Solver
Experienced Solver
Posts: 76
Joined: Sun Nov 29, 2015 12:46 pm

How write own widget?

Post by AndrzejB » Wed Sep 09, 2020 9:17 pm

Is any simple example? I suppose, most of wx widgets uses GTK but some are drawed. I want draw my widget : breadcrumb.

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4535
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How write own widget?

Post by ONEEYEMAN » Wed Sep 09, 2020 10:28 pm

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.

User avatar
doublemax
Moderator
Moderator
Posts: 15267
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How write own widget?

Post by doublemax » Thu Sep 10, 2020 5:16 am

You can use this as a starting point:
https://wiki.wxwidgets.org/Painting_your_custom_control
Use the source, Luke!

AndrzejB
Experienced Solver
Experienced Solver
Posts: 76
Joined: Sun Nov 29, 2015 12:46 pm

Re: How write own widget?

Post by AndrzejB » Thu Sep 10, 2020 6:16 am

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

AndrzejB
Experienced Solver
Experienced Solver
Posts: 76
Joined: Sun Nov 29, 2015 12:46 pm

Re: How write own widget?

Post by AndrzejB » Thu Sep 10, 2020 11:50 am

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?

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4535
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How write own widget?

Post by ONEEYEMAN » Thu Sep 10, 2020 4:08 pm

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.

User avatar
doublemax
Moderator
Moderator
Posts: 15267
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How write own widget?

Post by doublemax » Thu Sep 10, 2020 4:37 pm

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.
Use the source, Luke!

AndrzejB
Experienced Solver
Experienced Solver
Posts: 76
Joined: Sun Nov 29, 2015 12:46 pm

Re: How write own widget?

Post by AndrzejB » Fri Sep 11, 2020 7:51 am

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?

ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 4535
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: How write own widget?

Post by ONEEYEMAN » Fri Sep 11, 2020 7:56 am

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.

User avatar
doublemax
Moderator
Moderator
Posts: 15267
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How write own widget?

Post by doublemax » Fri Sep 11, 2020 8:28 am

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?
Use the source, Luke!

AndrzejB
Experienced Solver
Experienced Solver
Posts: 76
Joined: Sun Nov 29, 2015 12:46 pm

Re: How write own widget?

Post by AndrzejB » 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?

User avatar
doublemax
Moderator
Moderator
Posts: 15267
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How write own widget?

Post by doublemax » Fri Sep 11, 2020 10:44 am

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.
Use the source, Luke!

Post Reply