0

I'm creating a wxWidgets C++ calculator application. I have a series of wxTextCtrl's for the main expression text and other stuff. They are, of course, positioned using sizers so that they grow larger or smaller as I resize the window. However, if I maximize the window, their size successfully updates, but not if I then minimize it.

My app in a normal state:

Normal

Maximized application:

Maximized

And when I minimize it back:

Minimized

The wxTextCtrl's sizes eventually update and correct themselves when I resize the window, but this bug is kind of annoying.

Here's the code where these controls are defined:

text_controls.cpp

#include "main.h"

void Main::AddTextControls()
{
    auto sizer = new wxBoxSizer(wxVERTICAL);

    Chronology = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RIGHT);
    Chronology->SetBackgroundColour(wxColour(235, 235, 235));
    Chronology->SetForegroundColour(wxColour(105, 105, 105));
    Chronology->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {
        evt.Skip();
        Chronology->SetFont(
            wxFontInfo(wxSize(0, Chronology->GetSize().y / 1.5))
            .Family(wxFONTFAMILY_SWISS)
            .FaceName("Calibri Light")
        );
    });
    sizer->Add(Chronology, 4, wxEXPAND);

    Expression = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RIGHT);
    Expression->SetForegroundColour(wxColour(55, 55, 55));
    Expression->Bind(wxEVT_TEXT, &Main::OnTextChange, this);
    Expression->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {
        evt.Skip();
        Expression->SetFont(
            wxFontInfo(wxSize(0, Expression->GetSize().y / 1.3))
                .Family(wxFONTFAMILY_SWISS)
                .FaceName("Calibri")
                .Bold()
        );
    });
    sizer->Add(Expression, 10, wxEXPAND);

    //memoria
    auto memSizer = new wxBoxSizer(wxHORIZONTAL);

    MemText = new wxTextCtrl(this, wxID_ANY, "Memoria", wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER);
    MemText->SetBackgroundColour(wxColour(55, 55, 55));
    MemText->SetForegroundColour(wxColour(119, 119, 119));
    MemText->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {
        evt.Skip();
        MemText->SetFont(
            wxFontInfo(wxSize(0, MemText->GetSize().y / 1.3))
            .Family(wxFONTFAMILY_SWISS)
            .FaceName("Corbel")
        );
        });
    memSizer->Add(MemText, 25, wxEXPAND);

    Memory = new wxTextCtrl(this, wxID_ANY, "0", wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER | wxTE_RIGHT);
    Memory->SetBackgroundColour(wxColour(55, 55, 55));
    Memory->SetForegroundColour(wxColour(105, 105, 105));
    Memory->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {
        evt.Skip();
        Memory->SetFont(
            wxFontInfo(wxSize(0, Memory->GetSize().y / 1.3))
            .Family(wxFONTFAMILY_SWISS)
            .FaceName("Calibri Light")
        );
        });
    memSizer->Add(Memory, 100, wxEXPAND);

    sizer->Add(memSizer, 3, wxEXPAND);

    MainSizer->Add(sizer, 30, wxEXPAND);
}

Anybody got a solution? Also, I'm very new to wxWidgets.

EDIT: Followed a suggestion and added this snippet to my main frame constructor:

Main::Main() : wxFrame(nullptr, wxID_ANY, "IKE Calculator", wxDefaultPosition, wxSize(525, 650), wxDEFAULT_FRAME_STYLE)
{
    this->SetMinSize(wxSize(325, 450));

    FrameSize = this->GetSize();
    MainSizer = new wxBoxSizer(wxVERTICAL);

    this->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {
        evt.Skip();
        CallAfter(Layout()); //will be called later
        });

    this->SetBackgroundColour(wxColour(70, 73, 101));

    AddTextControls();
    AddMainButtons();
    AddButtons();

    this->SetSizer(MainSizer);
    MainSizer->Layout();
}

Getting a C2064 error in VS2019: The term doesn't return a function that accepts 0 arguments.

EDIT:

Changed CallAfter(Layout()); to CallAfter(&Main::Layout); and I'm getting the same error.

iKebab897
  • 73
  • 2
  • 7

1 Answers1

1

Let me reword your description:

"When I change the size of the window, manually or by maximizing it, everything goes well. But when I restore the window from a maximized status then fonts are wrongly updated"

If fonts must be changed accordingly with the size of the window then the size-event must be catched in the control. The handler gets a wxSizeEvent object with the new size of the control.
==>> So use this new size (i.e. evt.GetSize()) instead of control.GetSize() in your control->Bind(wxEVT_SIZE...) lambdas.

The issue comes from the fact that wxSizer's layout-process uses the current font in the control to calculate the new size. Thus, when you receive the size-event is too late to be taken the new font-size into account.
So, when the window is resized again, with a more or less same size as the last one, then old font size is the same as the new one, and then everything matches.

What can you do?
Catch the size event for the whole window (still use your handlers for changing the font) and call 'Layout()' after the handler finishes:

 MyFrame->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {
        evt.Skip();
        CallAfter(Layout()); //will be called later
        });

This second 'Layout` (first one is fired in sizer's code) may show a bit of flicker.

Ripi2
  • 7,031
  • 1
  • 17
  • 33
  • I tried adding this code but I'm getting an error (see the post, I edited it) – iKebab897 Jul 12 '21 at 10:26
  • @iKebab897 Ah, yes. [CallAfter](https://docs.wxwidgets.org/trunk/classwx_evt_handler.html#a63c7351618fd77330d80a250b3719519) should be used as `CallAfter(&Main::Layout)` where 'Main' is the frame's class in your app. – Ripi2 Jul 12 '21 at 18:22
  • I tried but nothing changed, see the edit in the post – iKebab897 Jul 14 '21 at 10:41