Reputation: 83
I'm writing a C++ wxWidgets calculator application, and I want the font of my wxTextCtrl's and my custom buttons to scale when I resize the window.
The problems are:
I'm using this code:
text_controls.cpp
MainText = new wxTextCtrl(this, wxID_ANY, "", wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxNO_BORDER);
MainText->SetForegroundColour(wxColour(55, 55, 55));
MainText->Bind(wxEVT_TEXT, &Main::OnTextChange, this);
MainText->Bind(wxEVT_SIZE, [this](wxSizeEvent& evt) {
evt.Skip();
MainText->SetFont(
wxFontInfo(wxSize(0, MainText->GetSize().y / 1.3))
.Family(wxFONTFAMILY_SWISS)
.FaceName("Lato")
.Bold()
);
});
And I'm using very similar code to generate the font in my custom button class file:
ikeButton.cpp
void ikeButton::render(wxDC& dc)
{
unsigned int w = this->GetSize().GetWidth();
unsigned int h = this->GetSize().GetHeight();
wxColour* bCol;
if (pressed) {
dc.SetBrush(*pressedBackgroundColor);
dc.SetTextForeground(*pressedTextColor);
bCol = pressedBorderColor;
}
else if (hovered) {
dc.SetBrush(*hoveredBackgroundColor);
dc.SetTextForeground(*hoveredTextColor);
bCol = hoveredBorderColor;
}
else {
dc.SetBrush(*backgroundColor);
dc.SetTextForeground(*textColor);
bCol = borderColor;
}
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(0, 0, w, h);
//bordo
if (borderTh && bCol != NULL)
{
dc.SetBrush(*bCol);
dc.DrawRectangle(0, 0, w, borderTh);
dc.DrawRectangle(w - borderTh, 0, borderTh, h);
dc.DrawRectangle(0, h - borderTh, w, borderTh);
dc.DrawRectangle(0, 0, borderTh, h);
}
//testo
dc.SetFont(
wxFontInfo(wxSize(0, this->GetSize().GetHeight() / 3))
.Family(wxFONTFAMILY_SWISS)
.FaceName("Lato")
.Light()
);
dc.DrawText(text, w / 2 - (GetTextExtent(text).GetWidth()),
h / 2 - (GetTextExtent(text).GetHeight()));
}
Upvotes: 1
Views: 454
Reputation: 3554
I'm really not sure what to do about the second problem. I think setting the font size from the size event when the frame is unmaximized causes something to be done in an unexpected order and temporarily breaks wxWidgets' layout system.
The only way I've found to workaround this so far is to use WinAPI calls to inject an extra Layout
call when the window is restored. To do this, add this declaration to your frame class:
#ifdef __WXMSW__
bool MSWHandleMessage(WXLRESULT *result,WXUINT message,
WXWPARAM wParam, WXLPARAM lParam) override;
#endif // __WXMSW__
The body of the MSWHandleMessage
method will need some extra constants that are defined in the wrapwin.h header. So in the code file for the frame, have this be the last #include
line:
#ifdef __WXMSW__
#include <wx/msw/wrapwin.h>
#endif // __WXMSW__
And then add this body for the MSWHandleMessage
#ifdef __WXMSW__
bool MyFrame::MSWHandleMessage(WXLRESULT *result, WXUINT message,
WXWPARAM wParam, WXLPARAM lParam)
{
if ( message == WM_SYSCOMMAND && wParam == SC_RESTORE )
{
CallAfter([this](){Layout();});
// We still want to do the default processing, so do not set a result
// and return true.
}
return wxFrame::MSWHandleMessage(result, message, wParam, lParam);
}
#endif // __WXMSW__
Obviously change 'MyFrame' to the name of your frame class.
But I can help with the first one.
I think there are 2 small problems with the current calculation of where to draw the text. First, I think GetTextExtent
should be called on the dc instead of the window. Second, I think there is a slight problem with order of the math operations. To center the text, I think the calculation for the x coordinate should be (w - GetTextExtent(text).GetWidth()) / 2
. A similar change should be made in the calculation for the y coordinate.
I would also store the text extent calculation instead of doing it twice:
wxSize textExtent = dc.GetTextExtent(text);
dc.DrawText(text, (w - textExtent.GetWidth())/ 2,
(h - textExtent.GetHeight())/2);
Feel free to skip this next part.
You can sometimes center text vertically better by basing the calculation on a font metric named ascent instead of the text height. Here's a diagram of what these font metrics mean from Microsoft
The reason ascent might be a better number to use is that the height will include several padding elements that might make the text look slightly uncentered.
wxSize textExtent = dc.GetTextExtent(text);
wxFontMetrics metrics = dc.GetFontMetrics();
dc.DrawText(text, (w - textExtent.GetWidth()) / 2, (h - metrics.ascent) / 2);
Upvotes: 2