Change the font size of all controls in the application (win forms)
Asked Answered
A

3

5

I have an application that needs to be adaptive to a range of different screen sizes (resolutions). Most of that I've done using table layout panels.

But some of the control (buttons and labels mostly) have too large font and the text doesn't fit in the control. So far I've managed change the font of some controls by using

            if (Screen.PrimaryScreen.Bounds.Width < 1440)
        {
            button_5.Font = new Font("Impact", button_5.Font.Size - 4);
        }

But that is too much text to add for every single control in the application.

Is there a way of changing the fonts of all the controls on the application at once? Or at least all controls on a form?

Anabaptist answered 31/7, 2017 at 22:31 Comment(3)
Every form is a control container where the Controls property lists all the controls on that form. When a control is itself a control container (panel,groupbox) then it has a Controls collection with the controls hosted by that container. It is relatively easy build a recursive function that loops over all controls of your formPrimer
Could you possibly give me an example of such a function so I can build what I need?Anabaptist
I've managed to set the fonts of all the controls in the table layout panel by using foreach (Control ctrl in tableLayoutPanel1.Controls) { ctrl.Font = new Font("Impact", ctrl.Font.Size - 4); } But no idea how to access all of the control of the whole form yet.Anabaptist
P
7

A simple recursive function will traverse all the controls in your form and change the font size. You need to test it against your controls and look at the effect because in this code there is no exception handling

public void SetAllControlsFont(ControlCollection ctrls)
{
    foreach(Control ctrl in ctrls)
    {
        if(ctrl.Controls != null)
            SetAllControlsFont(ctrl.Controls);

        ctrl.Font = new Font("Impact", ctrl.Font.Size - 4);

    }
}

You can call it from your toplevel form passing the initial form's control collection

SetAllControlsFont(this.Controls);
Primer answered 1/8, 2017 at 7:11 Comment(7)
That only changes the font for the first table layout panel but doesn't loop through the rest of the controls.Anabaptist
That should not be the case if this.Controls is the Form.Controls collection. The top level of the hierarchyPrimer
Could it have something to do with the fact that this.Controls only contains {System.Windows.Forms.TableLayoutPanel, BorderStyle: System.Windows.Forms.BorderStyle.None} which isn't even the actual control on the form and just the type of control.Anabaptist
I've managed to make it work by changing public void SetAllControlsFont(ControlCollection ctrls) to public void SetAllControlsFont(Control.ControlCollection ctrls) and instead of this.Controls I gave it tableLayoutPanel1.Controls, which contains all the other table layout panels inside it. Now it loops through al the panels and all the controls inside of those panels.Anabaptist
The problem was SetAllControlsFont(ctrl.Controls); could not convert from Cntrol.ControlCollection to Form.ControlCollection. Apparently those are different control collection types.Anabaptist
it seems that the TableLayoutPanel has its own implementation of the ControlCollection named TableLayourControlCollection. Perhaps you can try with a simple cast. Anyway if your are satisfied passing the TableLayoutControleCollection instead of this.Controls then there is no point to experiment. Glad to be of helpPrimer
Yeah I'm satisfied. Thank you.Anabaptist
F
3

Based on Steve's good answer, I would do the following improvements:

/// <summary>
/// Changes fonts of controls contained in font collection recursively. <br/>
/// <b>Usage:</b> <c><br/>
/// SetAllControlsFont(this.Controls, 20); // This makes fonts 20% bigger. <br/>
/// SetAllControlsFont(this.Controls, -4, false); // This makes fonts smaller by 4.</c>
/// </summary>
/// <param name="ctrls">Control collection containing controls</param>
/// <param name="amount">Amount to change: posive value makes it bigger, 
/// negative value smaller</param>
/// <param name="amountInPercent">True - grow / shrink in percent, 
/// False - grow / shrink absolute</param>
public static void SetAllControlsFontSize(
                   System.Windows.Forms.Control.ControlCollection ctrls,
                   int amount = 0, bool amountInPercent = true)
{
    if (amount == 0) return;
    foreach (Control ctrl in ctrls)
    {
        // recursive
        if (ctrl.Controls != null) SetAllControlsFontSize(ctrl.Controls,
                                                          amount, amountInPercent);
        if (ctrl != null)
        {
            float oldSize = (float)ctrl.Font.Size;
            float newSize = 
               (amountInPercent) ? oldSize + oldSize * ((float)amount / (float)100) 
                                 : oldSize + (float)amount;
            if (newSize < 4) newSize = 4; // don't allow less than 4
            var fontFamilyName = ctrl.Font.FontFamily.Name;
            ctrl.Font = new Font(fontFamilyName, newSize);
        };
    };
}

This allows to grow or shrink the font size in percent like:

SetAllControlsFontSize(this.Controls, 20); 

Or you can shrink the font size absolutely by a value of -4 like:

SetAllControlsFontSize(this.Controls, amount: -4, amountInPercent: false); 

In both examples, all fonts will be affected by the change. You do not need to know the font family names, each control can have different ones.

Combined with this answer you can auto-scale fonts in your application based on Windows settings (which you can find if you right click on the desktop, then select Display settings, Scale and layout and modify the value "Change the size of text, apps, and other items" - in Windows 10 versions newer than build 1809 this is (re-)named as "Make everything bigger"):

var percentage = GetWindowsScaling() - 100;
SetAllControlsFontSize(this.Controls, percentage); 

You should also limit the size to a certain maximum/minimum, based on your forms layout, e.g.

if (percentage > 80)  percentage = 80;
if (percentage < -20) percentage = -20;

Likewise this is true for absolute values - note that in the code there is already a limit set: Practically, a font cannot be smaller than 4 em - this is set as minimum limit (of course you can adapt that to your needs).

Fedora answered 6/3, 2020 at 11:16 Comment(2)
With Option Strict On, shouldn't it be: float newSize = Convert.ToSingle((amountInPercent) ? oldSize + oldSize * (amount / (double)100) : oldSize + amount);Videlicet
@Videlicet - Thank you for your hint, I have added some more explicit conversions to the code (I mean, I am converting everything related to oldsize and newsize in the expression to float now).Fedora
F
0

Just set the font of parent form. It will propagate through controls unless you set font on child control manually

Example code:

public MyForm()
{
    InitializeComponent();
    Font = new Font(new FontFamily("Microsoft Sans Serif"), 8f); //replace 8f with desired font size
}

From Control.Font docs:

Remarks

The Font property is an ambient property. An ambient property is a control property that, if not set, is retrieved from the parent control. For example, a Button will have the same BackColor as its parent Form by default.

Tested in .NetFramework 4.6.2 and .Net6

Fulgor answered 14/6, 2023 at 12:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.