如何在运行时更改应用程序字体? [英] How can change application font in runtime?

查看:148
本文介绍了如何在运行时更改应用程序字体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在运行时更改我的app字体?我的应用程序有MDI表单和子表单,我想要在主窗体(MDI表单)中更改应用程序字体并保存在设置中。但是当改变字体时,不会影响菜单和控制。



我尝试过的方法:



 fontDialog1.ShowDialog(); 
字体= fontDialog1.Font;



我也添加此代码以更改主窗体中的所有控件。

  foreach (控制c 控件中)
{
c。 Font = fontDialog1.Font;
}



但是当前形式的这种效果并不会改变子表单。

比添加此代码显示时更改子字体



  public  FrmChild()
{
font = myfont;
foreach (控制c 控件中)
{
c。 Font = fontDialog1.Font;
}
InitializeComponent();
}



但不是形式上的影响正确

解决方案

首先你需要了解在Win窗体的构造函数中调用'InitializeComponent设置所有控件的视觉属性,以及窗体本身。您的代码设置Win Form的所有顶级控件的Font属性,然后调用'InitializeComponent可能会覆盖它们因为:



这些环境如果你没有在运行时自己设置它们,那么像Font,BackgroundColor等视觉属性会从Windows的默认设置继承它们的值。



把你的之后的代码'InitializeComoponent将起作用;确实,表单上的'FontDialog组件的实例将具有默认的'字体值,并且您可以访问它而无需'显示'FontDialog:

的InitializeComponent(); 

foreach (控制c 控件中)
{
c.Font = fontDialog1.Font;

}

这是非常糟糕的编程习惯。



理想情况下,您的应用程序设计:



a。应该根据你想要修复的环境设置建立一个基本的视觉外观和感觉。



a.1。如果您想要使用具有相同外观的许多表单:创建模板表单,设置所有可视参数,创建该表单的多个实例,并更改它们以适应特定目标。虽然您可以从表单中创建继承的其他表单(通过在构造函数中设置Parent),但请注意,继承表单上的控件将在继承Forms时显示为已锁定,并且它很难处理以你想要的方式访问它们。



b。你想在哪里给用户运行时设置Font,FontStyle等等。



b.1。当然,使用FontDialog



如果在运行时应用Font更改,那么事情变得有趣的是控件或表单的'AutoScaleMode设置到'字体:你改变他们将调整大小的字体。你可能会,也可能不想要那样。即使用户将窗体或控件的AutoSize属性设置为false,如果AutoScaleMode设置为字体,控件,窗体,在更改字体时仍会更改大小。



我使用自定义扩展方法来更改控件字体或表单,并且它可选地是递归的,因此您可以进行一次调用并更改属于其他Control / ContaineControls的ControlCollection的所有控件。 br />


这是一个如何工作的简化草图:

 使用系统; 
使用 System.Drawing;
使用 System.Windows.Forms;

命名空间 YourNameSpace
{
public static class FontUtilities
{
public 静态 void SimpleChangeFont( this 控制目标,字体字体, bool doRecurse = false
{
target。字体=字体;
if (doRecurse)SimpleChangeFontRecurse(font,target.Controls);
}

private static void SimpleChangeFontRecurse(字体字体,Control.ControlCollection控件)
{
foreach (控制c 控件中)
{
c.Font = font;

if (c.Controls.Count > 0 )SimpleChangeFontRecurse(font,c.Controls);
}
}
}
}

因此,如果您在Method或EventHandler中执行此代码,并且存在对Mdi的有效引用ChildForm命名为'mdiChildForm1:

字体newFont = 字体( new 字体系列(   Consolas), 12  .0f ,FontStyle.Bold); 
mdiChildForm1.SimpleChangeFont(newFont, true );

表单及其中的每个Control,以及任何ContainerControls中的将所有字体设置为新字体。



您可以像我一样扩展此方法来处理以下内容:



a。容易:检查您正在考虑更改的字体是否与现有字体匹配,如果有,请不要更改。



b。更难一点:控制是否设置了自动调整大小属性的控件/表单,或将AutoScaleMode设置为某些模式设置,不执行或不执行,更改字体。



c。更难:允许传入每次代码评估是否更改当前Font时执行的自定义函数。因此,例如,如果Control FontStyle为'Italic,则无法更改字体。


请注意,您的第二个代码片段是构造函数,并且存在 InitializeComponent 调用表明您使用的是设计用控件填充表单。但是如果这样做,则在将任何控件添加到表单之前执行循环,这由 InitializeComponent 完成。所以,你的循环什么都不做。



把你的循环, InitializeComponent();另外,你可能需要递归遍历控件。



你只是在一个扁平的非递归循环中做这个事实表明你有一个扁平的设计:所有控件是形式的直接孩子。如果是这样的话,它表明一个非常糟糕的表单设计,几乎不可能正确维护。如果您的设计是分层的,那么您的遍历不起作用。



但是对于字体,您不必遍历任何内容,因为 Font 是一个环境属性 System.Windows.Forms.Control 。如果未设置字体,则从父控件中检索该字体: https://msdn.microsoft.com/en-us/library/system.windows.forms.control.font%28v=vs.110%29.aspx [ ^ ]。



这样,您只能在某些顶级父控件上设置字体,该控件也可以是表单实例。你的所有循环代码都是徒劳的。只需设置一个控件的字体,并在调用 InitializeComponent 后移动其赋值。



但我还是更好想法:做自己和客户的青睐,永远不要使用MDI。请参阅我过去的答案以获得解释和建议:

如何在WPF中创建MDI父窗口?

关于在WPF中使用MDI窗口的问题

MDIContainer给出错误

如何设置最大化的子表单,最小化最后一个子表单



-SA

how can change my app font in runtime? my app have MDI form and child form and i want change app font in main form (MDI form) and save in setting. but when change font, not effect in menu and contorl.

What I have tried:

fontDialog1.ShowDialog();
Font = fontDialog1.Font;


also i add this code for change all control in main form.

foreach (Control c in Controls)
          {
              c.Font = fontDialog1.Font;
          }


but this effect in current form and do not change child form.
than in add this code for change child font when show

public FrmChild()
        {
            font = myfont;
            foreach (Control c in Controls)
            {
                c.Font = fontDialog1.Font;
            }
            InitializeComponent();
        }


but not effect in form Correctly

解决方案

First you need to understand that the call to 'InitializeComponent in the Constructor of a Win Form sets the visual properties of all Controls, and the Form itself. Your code sets the Font property of all the top-level Controls of a Win Form, and then the call to 'InitializeComponent may over-write them because:

These ambient visual properties, like Font, BackgroundColor, etc. inherit their values from your default settings for Windows, if you do not set them yourself at run-time.

Putting your code after 'InitializeComoponent will work; it is true that an instance of the 'FontDialog Component on a Form will have a default 'Font value, and you can access that without ever having 'shown the 'FontDialog:

InitializeComponent();

foreach (Control c in Controls)
{
    c.Font = fontDialog1.Font;

}

This is very poor programming practice.

Ideally, your application design:

a. should establish a basic visual look and feel with ambient settings you wish fixed, set by you.

a.1. if you want to use a lot of Forms with the same look and feel: create a template form, and set all the visual parameters, create multiple instances of that Form, and alter them to fit specific goals. While you can create other Forms that inherit from a Form (by setting the Parent in the constructor), be aware that Controls on your inheritings Form will show-up in inheriting Forms as locked, and its tricky to access them in ways you might want.

b. where you want to give the user run-time abilities to set Font, FontStyle etc.

b.1. of course, use a FontDialog

Where things get "interesting" with applying a change of Font at run-time are when Controls, or Forms, have their 'AutoScaleMode set to 'Font: you change the Font they will resize. You may, or may not, want that. Even if the user sets the 'AutoSize property of Form or Control to 'false, if 'AutoScaleMode is set to 'Font, Controls, Forms, will still change size when their Font is changed.

I use a custom extension method for changing Font of Controls, or Forms, and it is optionally recursive, so you can make one call and change all Controls which are part of some other Control/ContaineControls 'ControlCollection.

Here's is a simplified sketch of how that works:

using System;
using System.Drawing;
using System.Windows.Forms;

namespace YourNameSpace
{
    public static class FontUtilities
    {
        public static void SimpleChangeFont(this Control target, Font font, bool doRecurse = false)
        {
            target.Font = font;
            if(doRecurse) SimpleChangeFontRecurse(font, target.Controls);
        }

        private static void SimpleChangeFontRecurse(Font font, Control.ControlCollection controls)
        {
            foreach (Control c in controls)
            {
                c.Font = font;
    
                if (c.Controls.Count > 0) SimpleChangeFontRecurse(font, c.Controls);
            }
        }
    }
}

So, if you executed this code in a Method, or EventHandler, and there was a valid reference to an Mdi ChildForm named 'mdiChildForm1:

Font newFont = new Font(new FontFamily("Consolas"), 12.0f, FontStyle.Bold);
mdiChildForm1.SimpleChangeFont(newFont, true);

The Form and every Control with in it, and within any of its ContainerControls would all have their Fonts set to the new Font.

You can, as I did, extend this method to handle things like:

a. easy: check whether the Font you are considering changing matches the existing Font and don't change it, if it does.

b. a little harder: offering control over whether Controls/Forms that have an AutoSize Property set, or AutoScaleMode set to certain Modes set, do, or do not, have their Font changed.

c. harder: enabling passing in custom functions that are executed each time the code evaluates whether or not to change the current Font. So, for example, you can not change a Font if the Control FontStyle is 'Italic.


Note that your second code fragment is a constructor, and the presence of the InitializeComponent call suggests that you are using the designed to fill the form with controls. But if you do so, you execute your loop before any controls are added to the form, which is done by InitializeComponent. So, your loop just does nothing.

Put your loop, after the InitializeComponent(); also, you may need to traverse controls recursively.

The fact that you simply do it in a flat non-recursive loop suggests that you have a flat design: all controls are immediate children of the form. If this is so, it indicate a really bad form design, which is nearly impossible to maintain properly. If your design is hierarchical, your traverse does not work.

But with fonts, you don't have to traverse anything, because Font is an ambient property of System.Windows.Forms.Control. If the font is not set, it is retrieved from the parent control: https://msdn.microsoft.com/en-us/library/system.windows.forms.control.font%28v=vs.110%29.aspx[^].

This way, you can set the font only on some top parent control, which can be also a form instance. All your loop code was written in vain. Just set only one control's font and move its assignment after the call to InitializeComponent.

But I have even better idea: do yourself and your customers great favor, never use MDI. Please see my past answers for the explanation and suggestions:
How to Create MDI Parent Window in WPF?,
Question on using MDI windows in WPF,
MDIContainer giving error,
How to set child forms maximized, last childform minimized.

—SA


这篇关于如何在运行时更改应用程序字体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆