Here is a complete compilable example of the most simplest implementation of a button-like control, implemented in more modern way than the one doublemax referenced above. It still does not use lambdas as I do not see their usefulness for this type of code here.
The control changes its appearance and mouse cursor shape when the left mouse button is pressed down on it, captures the mouse (so it is notified even about mouse events outside its client area), keeps the changed appearance and cursor until the left mouse button is released. It covers situations both where the mouse cursor is inside and outside the control when the mouse button is released. It also properly handles mouse capture being lost (taken over by another window).
If you understand the basics of wxWidgets or at least can use
the online documentation, it should not be difficult to understand what is going there.
I would suggest running the code as is, so you can see what gets logged after different user-control interactions.
Code: Select all
#include <wx/wx.h>
#include <wx/dcbuffer.h>
class MyControl : public wxControl
{
public:
MyControl(wxWindow* parent);
private:
void OnPaint(wxPaintEvent& event);
void OnMouseLeftDown(wxMouseEvent& event);
void OnMouseLeftUp(wxMouseEvent& event);
void OnMouseCaptureLost(wxMouseCaptureLostEvent& event);
wxSize DoGetBestClientSize() const override;
};
MyControl::MyControl(wxWindow* parent)
: wxControl(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
{
SetBackgroundStyle(wxBG_STYLE_PAINT);
Bind(wxEVT_PAINT, &MyControl::OnPaint, this);
Bind(wxEVT_LEFT_DOWN, &MyControl::OnMouseLeftDown, this);
Bind(wxEVT_LEFT_UP, &MyControl::OnMouseLeftUp, this);
Bind(wxEVT_MOUSE_CAPTURE_LOST, &MyControl::OnMouseCaptureLost, this);
}
void MyControl::OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxAutoBufferedPaintDC dc(this);
wxPen pen;
wxBrush brush;
if ( HasCapture() ) // draw in hot state
{
pen = *wxYELLOW_PEN;
brush = *wxRED_BRUSH;
wxLogMessage("Painting hot");
}
else
{
pen = *wxWHITE_PEN;
brush = *wxBLUE_BRUSH;
wxLogMessage("Painting default");
}
wxDCPenChanger penChanger(dc, pen);
wxDCBrushChanger brushChanger(dc, brush);
dc.DrawRectangle(GetClientRect());
}
void MyControl::OnMouseLeftDown(wxMouseEvent& event)
{
event.Skip();
CaptureMouse();
SetCursor(wxCursor(wxCURSOR_HAND));
wxLogMessage("Mouse left down");
Refresh(); // force redraw in "hot" state
Update();
}
void MyControl::OnMouseLeftUp(wxMouseEvent& event)
{
event.Skip();
if ( !HasCapture() )
{
wxLogMessage("Mouse left up but either capture was lost or mouse down was outside the control");
return;
}
ReleaseMouse();
if ( GetClientRect().Contains(event.GetPosition()) )
wxLogMessage("Mouse left up inside the control");
else
wxLogMessage("Mouse left up outside the control");
SetCursor(wxCursor(wxCURSOR_DEFAULT));
Refresh(); // force redraw
Update();
}
void MyControl::OnMouseCaptureLost(wxMouseCaptureLostEvent& event)
{
event.Skip();
SetCursor(wxCursor(wxCURSOR_DEFAULT));
Refresh(); // force redraw in "default" state
Update();
wxLogMessage("Mouse capture lost");
}
wxSize MyControl::DoGetBestClientSize() const
{
return wxSize(FromDIP(wxSize(200, 100)));
}
class MyApp : public wxApp
{
public:
bool OnInit()
{
wxFrame* frame = new wxFrame(nullptr, wxID_ANY, "Test", wxDefaultPosition, wxSize(500, 500));
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
MyControl* control = new MyControl(frame);
sizer->Add(control, wxSizerFlags().TripleBorder().CenterHorizontal());
wxTextCtrl* logCtrl = new wxTextCtrl(frame, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));
wxLog::DisableTimestamp();
sizer->Add(logCtrl, wxSizerFlags().Proportion(1).Expand().Border());
frame->SetSizer(sizer);
frame->Show();
return true;
}
}; wxIMPLEMENT_APP(MyApp);