Page 1 of 1

SetFont for whole application

Posted: Wed Sep 30, 2020 12:56 pm
by ValeV
Hi,

I am trying to change font for all text in the application.

I understand I should use SetFont() (viewtopic.php?t=28801), which I use on main wxPanel (all widgets are inside it).

Since I am using wxSmith, my problem is that the code for widgets is created automatically, so they are all created at the start, in the constructor of application MainFrame.

So have to change wxPanel font after GUI is created and then somehow update the GUI, so widgets will use new font. I tried using

Code: Select all

MainFrame->Refresh();

Code: Select all

MainFrame->Update();
and in App.cpp, after MainFrame is created shown, but font doesn't change.

I imagine Refresh() and Update() methods are not the ones to be used, but then I am out of ideas. So if anyone has solution, I'm all ears. :)

EDIT: silly me, I changed font in wxSmith GUI. Still, I am interested how this can be solved if I program it myself.

Re: SetFont for whole application

Posted: Wed Sep 30, 2020 3:55 pm
by PB
I do not think you can change the font for the whole application. However, you can easily change the font for a window and all its current children, grandchildren, and so on even after they have been created; see OnChangeFont() and SetFontInclChildren() in the code below.

Code: Select all

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

class MyFrame: public wxFrame
{
public:
    MyFrame() : wxFrame(nullptr, wxID_ANY, "Test")
    {
        wxBoxSizer* mainPanelSizer = new wxBoxSizer(wxVERTICAL);

        m_mainPanel = new wxPanel(this);

        mainPanelSizer->Add(new wxButton(m_mainPanel, wxID_ANY, "Change font"), wxSizerFlags().Expand().TripleBorder());
        mainPanelSizer->Add(new wxStaticText(m_mainPanel, wxID_ANY, "a static text"), wxSizerFlags().Expand().TripleBorder());
        mainPanelSizer->Add(new wxTextCtrl(m_mainPanel, wxID_ANY, "a text control"), wxSizerFlags().Expand().TripleBorder());

        Bind(wxEVT_BUTTON, &MyFrame::OnChangeFont, this);

        m_mainPanel->SetSizer(mainPanelSizer);
        SetSize(FromDIP(wxSize(800, 600)));
    }

private:
    wxPanel* m_mainPanel;

    static void SetFontInclChildren(wxWindow* window, const wxFont& font)
    {
        // set the font for this window
        window->SetFont(font);

        // and now set the font for all its children, their children, and so on...
        auto children = window->GetChildren();

        for ( auto node = children.GetFirst(); node; node = node->GetNext() )
        {
            wxWindow* current = node->GetData();
            SetFontInclChildren(current, font);
        }
    }

    void OnChangeFont(wxCommandEvent&)
    {
        wxFont newFont = wxGetFontFromUser(this, GetFont());

        if ( !newFont.IsOk() )
            return;

        SetFontInclChildren(this, newFont);
        m_mainPanel->Layout(); // the size of controls may have changed
    }
};

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        (new MyFrame())->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
Please notice that not all types of windows may accept the font change with SetFont(), the complex ones such as wxGrid may have different means of setting a font.

Additionally, in a real-word application a simple Layout() may not be good enough as the controls may become too large to fit the window after the font has been changed. So either the window must be resized to accommodate the larger controls or you need to use something like wxScrolledWindow instead of wxPanel so that the user can always easily access all the controls.

Re: SetFont for whole application

Posted: Thu Oct 01, 2020 6:15 am
by ValeV
Thank you for the example, I will take a look.