Simplest Form Of Creating Your Own wxButton

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
Everydaydiesel
Earned some good credits
Earned some good credits
Posts: 125
Joined: Wed Oct 28, 2015 9:48 pm

Simplest Form Of Creating Your Own wxButton

Post by Everydaydiesel »

I would like to create my own wxButton (mostly so I can control the background color when the user clicks).

I have never created my own controls before. Can someone show me the simplest form of how to do this to get me started?


Thanks in advance
User avatar
xaviou
Super wx Problem Solver
Super wx Problem Solver
Posts: 437
Joined: Mon Aug 21, 2006 3:18 pm
Location: Annecy - France
Contact:

Re: Simplest Form Of Creating Your Own wxButton

Post by xaviou »

If this is juste for buttons, you can have a look ad the "render" sample, witch does exactly this.

Regards
Xav'
My wxWidgets stuff web page : X@v's wxStuff
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Simplest Form Of Creating Your Own wxButton

Post by doublemax »

Use the source, Luke!
Everydaydiesel
Earned some good credits
Earned some good credits
Posts: 125
Joined: Wed Oct 28, 2015 9:48 pm

Re: Simplest Form Of Creating Your Own wxButton

Post by Everydaydiesel »

Thank you for the example. I have been trying to get this working.

Here is what I did. Created a class called wxCustomButton

//wxCustomButton.h

Code: Select all

#ifndef WXCUSTOMBUTTON_H
#define WXCUSTOMBUTTON_H

#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;

public:
    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);

    DECLARE_EVENT_TABLE()
};


BEGIN_EVENT_TABLE(wxCustomButton, wxPanel)

    EVT_MOTION(wxCustomButton::mouseMoved)
    EVT_LEFT_DOWN(wxCustomButton::mouseDown)
    EVT_LEFT_UP(wxCustomButton::mouseReleased)
    EVT_RIGHT_DOWN(wxCustomButton::rightClick)
    EVT_LEAVE_WINDOW(wxCustomButton::mouseLeftWindow)
    EVT_KEY_DOWN(wxCustomButton::keyPressed)
    EVT_KEY_UP(wxCustomButton::keyReleased)
    EVT_MOUSEWHEEL(wxCustomButton::mouseWheelMoved)

    // catch paint events
    EVT_PAINT(wxCustomButton::paintEvent)

END_EVENT_TABLE()



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);
    render(dc);
}

/*
 * 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);
    render(dc);
}

/*
 * 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 );
    else
        dc.SetBrush( *wxGREY_BRUSH );

    dc.DrawRectangle( 0, 0, buttonWidth, buttonHeight );
    dc.DrawText( text, 20, 15 );
}

void wxCustomButton::mouseDown(wxMouseEvent& event)
{
    pressedDown = true;
    paintNow();
}
void wxCustomButton::mouseReleased(wxMouseEvent& event)
{
    pressedDown = false;
    paintNow();

    wxMessageBox( wxT("You pressed a custom button") );
}
void wxCustomButton::mouseLeftWindow(wxMouseEvent& event)
{
    if (pressedDown)
    {
        pressedDown = false;
        paintNow();
    }
}

// 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) {}



#endif // WXCUSTOMBUTTON_H




As soon as I add a include to

Code: Select all

#include <wxCustomButton.h>
it gives me this error.

Code: Select all

I get "/usr/include/wx-3.0/wx/event.h|3988|error: ‘const wxEventTable wxWindowBase::sm_eventTable’ is protected|"
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Simplest Form Of Creating Your Own wxButton

Post by doublemax »

This seems to be an error in the wiki entry.

Code: Select all

class wxCustomButton : public wxWindow

Code: Select all

BEGIN_EVENT_TABLE(wxCustomButton, wxPanel)
The base class (wxWindow vs wxPanel) must be the same.
Use the source, Luke!
Everydaydiesel
Earned some good credits
Earned some good credits
Posts: 125
Joined: Wed Oct 28, 2015 9:48 pm

Re: Simplest Form Of Creating Your Own wxButton

Post by Everydaydiesel »

Thank you for the help!!!
Everydaydiesel
Earned some good credits
Earned some good credits
Posts: 125
Joined: Wed Oct 28, 2015 9:48 pm

Re: Simplest Form Of Creating Your Own wxButton

Post by Everydaydiesel »

How do I set the size of the control? This code draws the entire window green, I was thinking that it should only draw a small square slightly bigger then the button itself.


// main form.cpp

Code: Select all

void MainDialog::OnInit(wxInitDialogEvent& event)
{
        wxCustomButton* m_Button1;
       m_Button1 = new wxCustomButton(this, "my button");
}

// wxCustomButton.h

Code: Select all

void wxCustomButton::render(wxDC&  dc)
{
        dc.SetBackground(*wxGREEN_BRUSH);  // this paints the entire main/parent form green
        
        if (m_bPressedDown)
        {
            dc.Clear();
            dc.SetBrush( *wxRED_BRUSH );
            dc.DrawRectangle(0, 0, m_iButtonWidth, m_iButtonHeight);
            dc.DrawText(m_sButtonText, 0, 0);
    }
    else
    {
            dc.SetBrush( *wxGREY_BRUSH );
            dc.DrawRectangle(0, 0, m_iButtonWidth, m_iButtonHeight);
            dc.DrawText(m_sButtonText, 0, 0);
     }
} 
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Simplest Form Of Creating Your Own wxButton

Post by doublemax »

If a control is the only child of a wxTopLevelWindow (like wxDialog or wxFrame) it will get stretched to fill the whole client area. Use a wxPanel as parent for the control.

Code: Select all

void MainDialog::OnInit(wxInitDialogEvent& event)
{
  wxPanel *panel = new wxPanel(this, wxID_ANY);
  // warning: shadowing of member variable if there is one
  wxCustomButton* m_Button1 = new wxCustomButton(panel, "my button", wxPoint(10,10), wxSize(80,20));
}

Code: Select all

dc.DrawRectangle(0, 0, m_iButtonWidth, m_iButtonHeight);
It's not a good idea to store the button size in your own variables. Use the "real" size returned from GetSize() or GetClientSize().
Use the source, Luke!
Everydaydiesel
Earned some good credits
Earned some good credits
Posts: 125
Joined: Wed Oct 28, 2015 9:48 pm

Re: Simplest Form Of Creating Your Own wxButton

Post by Everydaydiesel »

Sorry to keep bothering, but I am actually quite lost here.

I can understand passing in the size of the button (because you need to draw it) but doesnt the top and left positions need to be managed by the container/parent object? In other words, shouldnt the canvas be the same size as the button and no bigger?

If I add one control then it takes up the entire window (like you said)
If I add two controls to the main window or a panel then it draws only a few pixels (25,25) estimated. I will continue to debug it.

I do apologize for the noob question, I am just trying to learn how to make my own controls.
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Simplest Form Of Creating Your Own wxButton

Post by doublemax »

I'm not sure what you're not understanding.
I can understand passing in the size of the button (because you need to draw it) but doesnt the top and left positions need to be managed by the container/parent object?
I only passed the wxPoint(10,10) as an example. If you put the control into a sizer, you can indeed just pass wxDefaultSize. However, if you wouldn't use sizers, you could position each control manually this way.
In other words, shouldnt the canvas be the same size as the button and no bigger?
The canvas *is* the button. But even if you intend to use it with a fixed size, it's good practice to assume it could have any size in your drawing code. Especially if you put it into a sizer.
Use the source, Luke!
Everydaydiesel
Earned some good credits
Earned some good credits
Posts: 125
Joined: Wed Oct 28, 2015 9:48 pm

Re: Simplest Form Of Creating Your Own wxButton

Post by Everydaydiesel »

It seems to be clipping the drawing when I add it to a wxPanel and I cannot figure out why. This is the simplest version of the code I could come up with.


// CustomButton.h

Code: Select all

#ifndef CUSTOMBUTTON_H
#define CUSTOMBUTTON_H

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

using namespace std;

class CustomButton : public wxWindow
{

public:
    CustomButton(wxWindow* parent, string sButtonText);

    void paintEvent(wxPaintEvent & evt);
    void paintNow();
    void render(wxDC& dc);

    DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(CustomButton, wxWindow)

    // catch paint events
    EVT_PAINT(CustomButton::paintEvent)

END_EVENT_TABLE()

CustomButton::CustomButton(wxWindow* parent, string sButtonText): wxWindow(parent, wxID_ANY)
{

}

void CustomButton::paintEvent(wxPaintEvent & evt)
{
    wxPaintDC dc(this);
    render(dc);
}

void CustomButton::paintNow()
{
    wxClientDC dc(this);
    render(dc);
}

void CustomButton::render(wxDC& dc)
{
    dc.SetBackground(*wxGREEN_BRUSH);
    dc.DrawRectangle(0, 0, 30, 50);
}

#endif // CUSTOMBUTTON_H



// main.cpp

Code: Select all

    wxPanel *panel = new wxPanel(this, wxID_ANY);
    panel->SetSize(500,500);
    CustomButton* btn = new CustomButton(panel, "test");
The code above gives me this
without_wxpanel.jpg
without_wxpanel.jpg (13.47 KiB) Viewed 13049 times





// if I add it to the main window it draws correctly.

Code: Select all

    CustomButton* btn = new CustomButton(this, "test");
with_wxpanel.jpg
with_wxpanel.jpg (13.28 KiB) Viewed 13049 times

why does it not draw the whole rectangle when it is added to a wxPanel?
User avatar
doublemax
Moderator
Moderator
Posts: 19114
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Simplest Form Of Creating Your Own wxButton

Post by doublemax »

You're not setting the size of the button anywhere.
Use the source, Luke!
Post Reply