How to TAB traversal on custom wxWindow controls

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
diogom12
Earned a small fee
Earned a small fee
Posts: 24
Joined: Sat Jun 13, 2020 6:07 am

How to TAB traversal on custom wxWindow controls

Post by diogom12 »

Hi,

im trying to build a custom button so I can get rounded buttons, so I derived from wxwindow and build a button, but Im not sure why this happened but the tab traversal is not working anymore, I tried to get focus events but it seems the focus is for the Panel/Frame not the childs on it (is also tried ChildFocusEvent with similar results).

I captured KeyEvents and sent the "wxEVT_COMMAND_BUTTON_CLICKED" , but it will only send the event for the first button in the wxpanel, hitting tab or arrow keys wont change that, im not sure where should I look for examples or anything related to that, can anyone help me?

this is the current code for the custombutton

Code: Select all

#ifndef CUSTOMCONTROLS_H
#define CUSTOMCONTROLS_H

#include "wx/wx.h"
#include "wx/graphics.h"
#include "../include/utils.h"

class wxCustomButton : public wxWindow
{
    public:
        wxCustomButton(wxPanel *parent, wxWindowID id, wxString text, const wxSize &size,
                       wxColour textcolour, wxColour bucolour, wxColour bacolour,
                       wxColour pressedcolour, bool rounded) :
                       wxWindow(parent, id, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL)
    {
        SetMinSize(size);
        this->text = text;
        this->rounded = rounded;
        this->bucolour = bucolour;
        this->bacolour = bacolour;
        this->textcolour = textcolour;
        this->pressedcolour = pressedcolour;
        pressedDown = false;
        rect.SetSize(size);

        Bind(wxEVT_LEFT_DOWN, &wxCustomButton::OnMouseDown, this);
        Bind(wxEVT_LEFT_UP, &wxCustomButton::OnMouseUp, this);
        Bind(wxEVT_ENTER_WINDOW, &wxCustomButton::OnMouseOver, this);
        Bind(wxEVT_LEAVE_WINDOW, &wxCustomButton::OnMouseOut, this);
        Bind(wxEVT_PAINT, &wxCustomButton::OnPaint, this);
        Bind(wxEVT_SET_FOCUS, &wxCustomButton::OnFocus, this);
        Bind(wxEVT_CHILD_FOCUS, &wxCustomButton::OnChildFocus, this);
        Bind(wxEVT_KEY_DOWN, &wxCustomButton::keyPressed, this);
        Bind(wxEVT_KEY_UP, &wxCustomButton::keyReleased, this);
    }
        inline void SetText(const wxString &newtext);

    protected:
        bool pressedDown;
        bool rounded;
        wxRect rect;
        wxString text;
        wxColour bucolour;
        wxColour bacolour;
        wxColour textcolour;
        wxColour pressedcolour;

        inline void OnPaint(wxPaintEvent &evt);
        inline void render();
        inline void paintNow();

        inline void OnFocus(wxFocusEvent& evt);
        inline void OnChildFocus(wxChildFocusEvent& evt);
        inline void OnMouseDown(wxMouseEvent& event);
        inline void OnMouseUp(wxMouseEvent &event);
        inline void OnMouseOver(wxMouseEvent &event);
        inline void OnMouseOut(wxMouseEvent &event);
        inline void keyPressed(wxKeyEvent &event);
        inline void keyReleased(wxKeyEvent &event);
};

void wxCustomButton::keyPressed(wxKeyEvent &event)
{
    TRACE_FUNC_CALL();

    if (event.GetKeyCode() == WXK_RETURN || event.GetKeyCode() == WXK_SPACE)
    {
        TRACE_LF("sending event");
        wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
        evt.SetEventObject(this);
        HandleWindowEvent(evt);
        event.Skip();
    }

    TRACE_LF("key code = %d", (int)event.GetKeyCode());
}

void wxCustomButton::keyReleased(wxKeyEvent &event)
{
    TRACE_FUNC_CALL();
}

void wxCustomButton::OnFocus(wxFocusEvent &evt)
{
    TRACE_FUNC_CALL();
}

void wxCustomButton::OnChildFocus(wxChildFocusEvent &evt)
{
    TRACE_FUNC_CALL();
}


void wxCustomButton::SetText(const wxString &newtext)
{
    TRACE_FUNC_CALL();

    this->text = newtext;
    paintNow();
    this->RefreshRect(rect);
}

void wxCustomButton::OnPaint(wxPaintEvent &evt)
{
    paintNow();
}

void wxCustomButton::paintNow()
{
    wxPaintDC dc(this);

    dc.SetBackground(bacolour);
    dc.Clear();

    wxGraphicsContext *gc = wxGraphicsContext::Create(dc);

    if (pressedDown)
    {
        gc->SetPen(*wxTRANSPARENT_PEN);
        gc->SetBrush(pressedcolour);
    }
    else
    {
        gc->SetPen(*wxTRANSPARENT_PEN);
        gc->SetBrush(bucolour);
    }

    wxGraphicsPath path = gc->CreatePath();

    if (rounded)
    {
        gc->DrawRoundedRectangle(rect.x, rect.y, rect.width, rect.height, 15);
        path.AddRoundedRectangle(rect.x, rect.y, rect.width, rect.height, 15);
    }
    else
    {
        gc->DrawRectangle(rect.x, rect.y, rect.width, rect.height);
        path.AddRectangle(rect.x, rect.y, rect.width, rect.height);
    }

    gc->FillPath(path);
    gc->StrokePath(path);
    delete gc;

    dc.SetTextForeground(textcolour);
    dc.DrawLabel(text, rect, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL);
}

void wxCustomButton::OnMouseDown(wxMouseEvent& event)
{
    pressedDown = true;
    paintNow();
    this->RefreshRect(rect);
}

void wxCustomButton::OnMouseUp(wxMouseEvent& event)
{
    TRACE_FUNC_CALL();

    pressedDown = false;
    paintNow();
    this->RefreshRect(rect);

    wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
    evt.SetEventObject(this);
    HandleWindowEvent(evt);
}

void wxCustomButton::OnMouseOut(wxMouseEvent& event)
{
    if (pressedDown)
    {
        pressedDown = false;
        paintNow();
    }
}

void wxCustomButton::OnMouseOver(wxMouseEvent& event)
{
}
#endif
thanks
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to TAB traversal on custom wxWindow controls

Post by doublemax »

Try deriving from wxPanel instead of wxWindow.

A few unrelated comments:
- get rid of the paintNow() method, just have a paint event handler. If you want to force a redraw, call Refresh()

- you should pass the "size" parameter through to the base ctor
- this will make the SetMinSize() call unnecessary

- if you want your control to behave nicely inside sizers, override wxWindow::DoGetBestClientSize()
https://docs.wxwidgets.org/trunk/classw ... 3e3d02ee89
Use the source, Luke!
diogom12
Earned a small fee
Earned a small fee
Posts: 24
Joined: Sat Jun 13, 2020 6:07 am

Re: How to TAB traversal on custom wxWindow controls

Post by diogom12 »

thanks, the wxPanel did the trick, but it doesnt render the outside selection automatically, I guess I will have to code this too, I think its triggering the focus events correctly now, so it should be easier.

also, it makes sense about the paintNow and size, im just calling refreshrect now instead..

thanks again.
diogom12
Earned a small fee
Earned a small fee
Posts: 24
Joined: Sat Jun 13, 2020 6:07 am

Re: How to TAB traversal on custom wxWindow controls

Post by diogom12 »

Again about the doing such custom controls, I want to the same for wxTextCtrl, (I want rounded borders), is the way to do it without recreating the full control + events?
New Pagodi
Super wx Problem Solver
Super wx Problem Solver
Posts: 466
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: How to TAB traversal on custom wxWindow controls

Post by New Pagodi »

Create a borderless text control and put in in another window and draw a rounded border on that second window.
User avatar
doublemax
Moderator
Moderator
Posts: 19116
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: How to TAB traversal on custom wxWindow controls

Post by doublemax »

diogom12 wrote: Mon Jun 07, 2021 6:48 pm thanks, the wxPanel did the trick, but it doesnt render the outside selection automatically, I guess I will have to code this too
If you mean the focus rectangle, wxRendererNative::DrawFocusRect might help.
https://docs.wxwidgets.org/trunk/classw ... 9559a8c4c9
Use the source, Luke!
diogom12
Earned a small fee
Earned a small fee
Posts: 24
Joined: Sat Jun 13, 2020 6:07 am

Re: How to TAB traversal on custom wxWindow controls

Post by diogom12 »

New Pagodi wrote: Mon Jun 07, 2021 7:44 pm Create a borderless text control and put in in another window and draw a rounded border on that second window.
thats a pretty good idea, thanks
Post Reply