Search code examples
c++wxwidgets

Im trying to make custom buttons for a GUI with wxwidgets


Im trying to make a simple GUI with 2 custom buttons. The 2 buttons are made as Panels and I can't seem to make the panels switch color when I press on them. At the moment they give the same output when I press them but that has to change but im not sure how at the moment either.

This is the code and if you have an idea of how I could fix my problem I would love your input :D.

PS: There are multiple #Include <wx/wx.h> in the code and so on because I make .h files for my classes !

Image of GUI the code gives: enter image description here

#include <wx/wx.h>

class MyPanel : public wxPanel {

    bool pressedDown;
    wxString text;


    public:
    MyPanel(wxWindow *parent, wxString text);

    void paintEvent(wxPaintEvent & evt);
    void paintNow();
        
    void render(wxDC& dc);
        
    // some useful events
    
    void mouseDown(wxMouseEvent& event);
    void mouseReleased(wxMouseEvent& event);
    void mouseLeftWindow(wxMouseEvent& event);
        
    DECLARE_EVENT_TABLE()


}; 

#include "Panels.h"
#include <iostream>

BEGIN_EVENT_TABLE(MyPanel,wxWindow)

    EVT_LEFT_DOWN(MyPanel::mouseDown)
    EVT_LEFT_UP(MyPanel::mouseReleased)
    EVT_LEAVE_WINDOW(MyPanel::mouseLeftWindow)
    

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

END_EVENT_TABLE()

MyPanel::MyPanel(wxWindow *parent, wxString text) : wxPanel(parent, wxID_ANY){
    this->text = text;
    pressedDown = false;
}

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

void MyPanel::paintNow()
{
    // depending on your system you may need to look at double-buffered dcs
    wxClientDC dc(this);
    render(dc);
}

void MyPanel::render(wxDC&  dc)
{
    if (pressedDown)
        dc.SetBrush( *wxRED_BRUSH );
        else
        dc.SetBrush( *wxGREY_BRUSH );
    
    dc.DrawText( text, 20, 15 );
}

void MyPanel::mouseDown(wxMouseEvent& event)
{
    pressedDown = true;
    paintNow();
}

void MyPanel::mouseReleased(wxMouseEvent& event)
{
    pressedDown = false;
    paintNow();

    std::cout << "Pressed" << std::endl;
}
void MyPanel::mouseLeftWindow(wxMouseEvent& event)
{
    if (pressedDown)
    {
        pressedDown = false;
        paintNow();
    }
}

#include <wx/wx.h>

class AppFrame : public wxFrame
{
public:
   AppFrame(const wxString& title, const wxPoint &pos, const wxSize &size);

};

#include <wx/wx.h>
#include "AppFrame.h"
#include "Panels.h"

MyPanel* m_btn_1;
MyPanel* m_btn_2;


AppFrame::AppFrame(const wxString &title, const wxPoint &pos, const wxSize &size)
: wxFrame(nullptr, wxID_ANY, title, pos, size) {

    wxInitAllImageHandlers();
    
    m_btn_1 = new MyPanel( this, wxT("PickUp") );
    m_btn_1->SetBackgroundColour(wxColor(100, 100, 200));

    m_btn_2 = new MyPanel( this, wxT("PlaceDown") );
    m_btn_2->SetBackgroundColour(wxColor(100, 200, 100));

    wxBoxSizer *sizer = new wxBoxSizer(wxVERTICAL);
    sizer->Add(m_btn_1, 1, wxEXPAND | wxLEFT | wxTOP | wxRIGHT, 10);
    sizer->Add(m_btn_2, 1, wxEXPAND | wxALL, 10);

    this->SetSizerAndFit(sizer);
Centre();
}

#include <wx/wx.h>

class App : public wxApp
{
public:
   virtual bool OnInit();
};
 
// This defines the equivalent of main() for the current platform.
DECLARE_APP(App);

#include "main.h"
#include <wx/wx.h>
#include "AppFrame.h"

IMPLEMENT_APP(App)

bool App::OnInit(){
    AppFrame *frame = new AppFrame("Frame",wxDefaultPosition,wxDefaultSize);
    frame->Show(true);
    return true;
}



Solution

  • There are 2 big problems in this code:

    1. You must not use wxClientDC at all, see the note in its documentation. Just call Refresh() instead to redraw the window.
    2. You must capture the mouse when reacting to mouse down events as otherwise you're going to have problems if the user presses the button inside the window and releases it outside of it (without the capture you won't get the latter event at all).

    There might be other problems I didn't notice, but you need to fix at least these ones.