Painting your custom control

From WxWiki
Jump to: navigation, search

The following code demonstrates how to start to create a custom widget (that you paint yourself) by deriving from wxWindow. It creates a simple basic button that does nothing useful but can be used as starting point.

Not that although this example draws a rectangular component, nothing prevents you from changing the paint method to draw any shape you fancy.

Some common mistakes

  • Derive from wxWindow for simple (i.e. not containing children) controls, not from wxControl, which is the base class for the native controls.
  • Do not use wxPaintDC outside paint events (use wxClientDC if you absolutely have to but better limit all your drawing to wxEVT_PAINT handler).
  • Do not draw something on a wxClientDC and then expect it will stay there forever (wrong because your window manager may throw away your drawing at any time - e.g. if the window is minimized or hidden behind something else - and will expect you can draw it back later when receiving a paint event) i.e. always enable the paint event to draw everything. The best way to deal with this is to separate state/data from view. (The render routine reads variables describing current state and draws according to these variables. When something needs to change, don't render it straight ahead; instead, update the variables and call for a repaint - if well-coded, your paint routine should catch the change)


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

class wxCustomButton : public wxWindow

    bool pressedDown;
    wxString text;
    static const int buttonWidth = 200;
    static const int buttonHeight = 50;
    wxCustomButton(wxFrame* parent, wxString text);
    void paintEvent(wxPaintEvent & evt);
    void paintNow();
    void render(wxDC& dc);
    // some useful events
    void mouseMoved(wxMouseEvent& event);
    void mouseDown(wxMouseEvent& event);
    void mouseWheelMoved(wxMouseEvent& event);
    void mouseReleased(wxMouseEvent& event);
    void rightClick(wxMouseEvent& event);
    void mouseLeftWindow(wxMouseEvent& event);
    void keyPressed(wxKeyEvent& event);
    void keyReleased(wxKeyEvent& event);

BEGIN_EVENT_TABLE(wxCustomButton, wxPanel)


    // catch paint events


wxCustomButton::wxCustomButton(wxFrame* parent, wxString text) :
 wxWindow(parent, wxID_ANY)
    SetMinSize( wxSize(buttonWidth, buttonHeight) );
    this->text = text;
    pressedDown = false;

 * Called by the system of by wxWidgets when the panel needs
 * to be redrawn. You can also trigger this call by
 * calling Refresh()/Update().

void wxCustomButton::paintEvent(wxPaintEvent & evt)
    // depending on your system you may need to look at double-buffered dcs
    wxPaintDC dc(this);

 * Alternatively, you can use a clientDC to paint on the panel
 * at any time. Using this generally does not free you from
 * catching paint events, since it is possible that e.g. the window
 * manager throws away your drawing when the window comes to the
 * background, and expects you will redraw it when the window comes
 * back (by sending a paint event).
void wxCustomButton::paintNow()
    // depending on your system you may need to look at double-buffered dcs
    wxClientDC dc(this);

 * Here we do the actual rendering. I put it in a separate
 * method so that it can work no matter what type of DC
 * (e.g. wxPaintDC or wxClientDC) is used.
void wxCustomButton::render(wxDC&  dc)
    if (pressedDown)
        dc.SetBrush( *wxRED_BRUSH );
        dc.SetBrush( *wxGREY_BRUSH );
    dc.DrawRectangle( 0, 0, buttonWidth, buttonHeight );
    dc.DrawText( text, 20, 15 );

void wxCustomButton::mouseDown(wxMouseEvent& event)
    pressedDown = true;
void wxCustomButton::mouseReleased(wxMouseEvent& event)
    pressedDown = false;
    wxMessageBox( wxT("You pressed a custom button") );
void wxCustomButton::mouseLeftWindow(wxMouseEvent& event)
    if (pressedDown)
        pressedDown = false;

// currently unused events
void wxCustomButton::mouseMoved(wxMouseEvent& event) {}
void wxCustomButton::mouseWheelMoved(wxMouseEvent& event) {}
void wxCustomButton::rightClick(wxMouseEvent& event) {}
void wxCustomButton::keyPressed(wxKeyEvent& event) {}
void wxCustomButton::keyReleased(wxKeyEvent& event) {}

// ----------------------------------------
// how-to-use example

class MyApp: public wxApp
    wxFrame *frame;
    wxCustomButton* m_btn_1;
    wxCustomButton* m_btn_2;
    wxCustomButton* m_btn_3;


    bool OnInit()
        // make sure to call this first
        wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
        frame = new wxFrame(NULL, wxID_ANY, wxT("Hello wxDC"), wxPoint(50,50), wxSize(800,600));
        // then simply create like this
        m_btn_1 = new wxCustomButton( frame, wxT("My Custom Button 11") );
        sizer->Add(m_btn_1, 0, wxALL, 5);
        m_btn_2 = new wxCustomButton( frame, wxT("Hello World!") );
        sizer->Add(m_btn_2, 0, wxALL, 5);
        m_btn_3 = new wxCustomButton( frame, wxT("Foo Bar") );
        sizer->Add(m_btn_3, 0, wxALL, 5);
        return true;



If you have flickering problems, see Drawing_on_a_panel_with_a_DC#To_avoid_flickering