2010-06-04 165 views
32

当使用非默认字体时,Form.AutoScaleMode属性和固定大小的控件一起出现了一些问题。我煮沸它归结为一个简单的测试应用(的WinForms 2.0)只有一种形式中,一些固定尺寸的控制和以下性质:AutoScaleMode更改默认字体的问题

class Form1 : Form 
{ 
    // ... 
    private void InitializeComponent() 
    { 
     // ... 
     this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); 
     this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; 
     this.Font = new System.Drawing.Font("Tahoma", 9.25F); 
     // ... 
    } 
} 

在96DPI时,Windows XP,形式看起来正确地像这样96 DPI例如:

96 dpi WinForm

在120 DPI,Windows XP中,Windows窗体自动缩放功能产生本120 DPI例如:

Previous WinForm scaled to 120 dpi

正如您所看到的,组合框,按钮,列表或树视图正确缩放,多行文本框在垂直轴上变得太大,而固定大小的标签在垂直和水平方向上都不能正确缩放。似乎是在.NET框架中的错误?

编辑:一些提示:字体更改只适用于包含窗体,控件从窗体继承它们的字体。如果可能,我想保持这种方式。

使用默认字体(Microsoft Sans Serif 8.25pt),不会发生此问题。使用AutoScaleMode = Font(当然具有足够的AutoScaleDimensions)根据Font设置的时间(在AutoScaleMode更改之前或之后),根本不会缩放或缩放。该问题不是特定于“Tahoma”字体,它也发生在Microsoft Sans Serif 9.25pt。

是的,我已经读过这个SO帖子 high DPI problems 但它并没有真正帮助我。

任何建议如何来解决这个问题?

编辑2:关于我的意图的一些额外信息:我已经有大约50个工作的固定大小的对话框,有几百个正确放置的固定大小的控件。他们从旧的C++ GUI框架迁移到C#/ Winforms,这就是为什么他们都是固定大小。所有这些都使用9.25pt字体在96 dpi下显得很好。在旧的框架下,缩放到120 dpi的效果很好 - 所有固定大小的控件在两个维度上缩放比例相等。上周,我们在切换到120 dpi时在WinForms下检测到了这种奇怪的缩放行为。你可以想象,现在我们的大多数对话框在120dpi以下看起来都很糟糕。我正在寻找一种解决方案,避免完全重新设计所有这些对话框。

EDIT3:为了测试这种行为,恕我直言,当开发环境位于96 dpi(至少,这就是我所做的)时,建立一个120 dpi的虚拟Windows XP环境是个好主意。通常需要在Win XP下重新启动96到120 dpi,否则你不会看到真正发生的事情。

// As requested: the source code of Form1.cs 
namespace DpiChangeTest 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
      Font f = this.textBox1.Font; 
     } 
    } 
} 

// here the source of Form1.Designer.cs: 
namespace DpiChangeTest 
{ 
    partial class Form1 
    { 
     private System.ComponentModel.IContainer components = null; 

     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Forms Designer generated code 

     private void InitializeComponent() 
     { 
      System.Windows.Forms.ListViewItem listViewItem2 = new System.Windows.Forms.ListViewItem("A list view control"); 
      System.Windows.Forms.TreeNode treeNode2 = new System.Windows.Forms.TreeNode("A TreeView control"); 
      this.button1 = new System.Windows.Forms.Button(); 
      this.groupBox1 = new System.Windows.Forms.GroupBox(); 
      this.textBox1 = new System.Windows.Forms.TextBox(); 
      this.label1 = new System.Windows.Forms.Label(); 
      this.listView1 = new System.Windows.Forms.ListView(); 
      this.treeView1 = new System.Windows.Forms.TreeView(); 
      this.SuspendLayout(); 
      // 
      // button1 
      // 
      this.button1.Location = new System.Drawing.Point(12, 107); 
      this.button1.Name = "button1"; 
      this.button1.Size = new System.Drawing.Size(150, 70); 
      this.button1.TabIndex = 0; 
      this.button1.Text = "Just a button"; 
      this.button1.UseVisualStyleBackColor = true; 
      // 
      // groupBox1 
      // 
      this.groupBox1.Location = new System.Drawing.Point(12, 12); 
      this.groupBox1.Name = "groupBox1"; 
      this.groupBox1.Size = new System.Drawing.Size(150, 70); 
      this.groupBox1.TabIndex = 1; 
      this.groupBox1.TabStop = false; 
      this.groupBox1.Text = "Just a groupbox"; 
      // 
      // textBox1 
      // 
      this.textBox1.Location = new System.Drawing.Point(180, 12); 
      this.textBox1.Multiline = true; 
      this.textBox1.Name = "textBox1"; 
      this.textBox1.Size = new System.Drawing.Size(150, 70); 
      this.textBox1.TabIndex = 2; 
      this.textBox1.Text = "A multiline text box"; 
      // 
      // label1 
      // 
      this.label1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; 
      this.label1.Location = new System.Drawing.Point(179, 107); 
      this.label1.Name = "label1"; 
      this.label1.Size = new System.Drawing.Size(150, 70); 
      this.label1.TabIndex = 3; 
      this.label1.Text = "A label with AutoSize=False"; 
      // 
      // listView1 
      // 
      this.listView1.Items.AddRange(new System.Windows.Forms.ListViewItem[] { 
      listViewItem2}); 
      this.listView1.Location = new System.Drawing.Point(12, 201); 
      this.listView1.Name = "listView1"; 
      this.listView1.Size = new System.Drawing.Size(150, 70); 
      this.listView1.TabIndex = 4; 
      this.listView1.UseCompatibleStateImageBehavior = false; 
      // 
      // treeView1 
      // 
      this.treeView1.Location = new System.Drawing.Point(179, 201); 
      this.treeView1.Name = "treeView1"; 
      treeNode2.Name = "Knoten0"; 
      treeNode2.Text = "A TreeView control"; 
      this.treeView1.Nodes.AddRange(new System.Windows.Forms.TreeNode[] { 
      treeNode2}); 
      this.treeView1.Size = new System.Drawing.Size(150, 70); 
      this.treeView1.TabIndex = 5; 
      // 
      // Form1 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi; 
      this.ClientSize = new System.Drawing.Size(343, 289); 
      this.Controls.Add(this.treeView1); 
      this.Controls.Add(this.listView1); 
      this.Controls.Add(this.label1); 
      this.Controls.Add(this.textBox1); 
      this.Controls.Add(this.button1); 
      this.Controls.Add(this.groupBox1); 
      this.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.25F); 
      this.Name = "Form1"; 
      this.Text = "Form1"; 
      this.ResumeLayout(false); 
      this.PerformLayout(); 

     } 

     #endregion 

     private System.Windows.Forms.Button button1; 
     private System.Windows.Forms.GroupBox groupBox1; 
     private System.Windows.Forms.TextBox textBox1; 
     private System.Windows.Forms.Label label1; 
     private System.Windows.Forms.ListView listView1; 
     private System.Windows.Forms.TreeView treeView1; 
    } 
} 

// and Main.cs 
    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 
     Application.Run(new Form1()); 
    } 

回答

33

我终于找到了我的问题的答案。简而言之,如果单独设置每个控件的字体而不是设置包含表单的字体,则不会产生这种效果。这样,自动缩放功能就像它应该那样工作。有趣的是,即使AutoScaleMode属性设置为AutoScaleMode.Dpi,但不仅在设置为AutoScaleMode.Font时,设置控件的字体才会更改自动缩放行为。

作为一个实用的解决方案,我们创建了一个小型命令行程序,读取设计器。cs文件,扫描所有控件是否具有明确的字体分配,如果不是,则将该分配添加到新创建的设计器代码副本中。我们将这个程序嵌入到我们的自动测试套件中,所以无论何时一个表单获得新的控件,或添加一个新表单,并且dev忘记添加明确的字体分配,测试都将失败。在这之间,我们从我第一次(4年前)提出这个问题的时候开始就有了这个解决方案,并且从那时起,我们多次从缩放问题中解脱出来。

+4

我遇到了同样的问题。控制不响应'Scale'(或受保护的“ScaleControl”)方法来缩放其'Font'。我正在玩的解决方案是递归迭代所有控件,并且(神奇地)确定字体是否应该是什么,并修复它。尽管如此,我仍然在努力研究一些陷阱。如果我得到解决方案,会报告回来 – 2011-11-24 19:14:36

+0

我感到你的痛苦。我在同一条船上,似乎这是一个普遍而且非常严重的问题,但似乎没有人解决它或提供答案。 – 2012-04-09 18:02:18

+0

@ShacharWeis:对于我们的情况,我们有一个解决方案。我们创建了一个小程序(小于200 LOC),它读取designer.cs文件,扫描所有控件是否具有明确的字体分配,如果没有,则将该分配添加到代码中。 – 2012-04-16 16:11:57

1

我能够解决与VS 2008上的紧凑框架3.5类似的问题。在我的情况下,我有一个tabcontrol,并且每个tabpage有一个面板,并且所有都停靠为他们的​​父母。每个面板都包含多个标签和文本框控件,因此这个想法是当用户打开滚动条出现在右侧的SIP(软输入面板/键盘)时,文本框控件的宽度将缩放以避免绘制额外的水平滚动条。

我最初的尝试将窗体的自动缩放模式设置为dpi,每个tabpages的autoscroll属性设置为true,并将每个面板的autoscroll属性设置为true。每个标签都固定在顶部,左侧,每个文本框控件都固定在左侧,顶部和右侧。这些表单是在屏幕宽度为240像素的设计器中创建的,并且在具有480像素屏幕宽度的vga设备上运行时,文本框将被涂上足够2个滚动条的足够空间(可能是一个用于tabpage和一个用于面板),即使滚动条没有出现。当激活SIP时,行为是正确的,因为所有的文本框都调整了大小,但我仍然在文本框右侧和滚动条之间有40个像素的死区。

我能够通过简单地将面板的autoscroll属性设置为false来解决问题,然后在激活SIP时将其设置为true。这样就可以在任何像素宽度上自动缩放屏幕的全宽,并在滚动条被激活或停用时动态调整文本框控件的大小。作为一个说明,紧凑框架(3.5)没有字体自动缩放模式(只有none,dpi和继承),但我尝试重置每个文本框控件的字体,原始作者建议,但是这个对控件的自动缩放没有任何影响。

1

我也发现奇怪的行为,并且在尝试自动缩放我的应用程序中的控件(及其相关字体)时遇到类似的问题,以响应大小或分辨率更改。

对于它的价值,这里是什么,我一直在试图申请一个手动修复一个简要介绍:

首先,在应用程序启动,我通过访问成员捕获用户的系统分辨率Screen :: PrimaryScreen属性,并根据与开发时系统的百分比差异以编程方式调整窗体大小。这个新的表格大小被存储并用作所有未来调整的基本大小。另外,通过在运行时更改表单的大小,它会调用我处理的SizeChanged事件来执行缩放。概括地说,事件处理程序将执行以下操作:

  • 大小调整所有控件根据新的宽度和高度的百分数的用户选择的尺寸后,是否从鼠标或预定义的大小。

  • 更改由新的比例系数与每个控件关联的字体大小

从理论上讲,如果控制移动到基于百分比形式的尺寸改变一个新的位置,应该让他们相对于所有其他控件。当然,每次用户更改表单大小时,都会发生上述情况,而不仅仅是在初始运行时。

我不确定这个解决方案是否愚蠢,但是我花了时间,或者浪费了,与AutoScale,AutoSize和Anchoring作斗争的时间都是天文数字。我没有试图劫持你的部分,Doc,我只是想我会与你分享我的思维过程,也许重新提出这个话题,希望有人对这个噩梦有一些更深入的了解。

0

对于为每个控件进行更改所接受的解决方案: 您是否测试过更改容器的字体,但是再次设置了AutoScaleXXX值?

喜欢的东西:

this.SuspendLayout(); 
this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F); 
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; // Font in this case 
this.Font = new Font(....); // set your new font 
this.ResumeLayout(); 

我这样做时动态添加控件,但不能改变字体。

3

让这个令人沮丧的问题导致窗体上的间距变得不相称,但是,将AutoScaleMode更改为“无”,问题完全消失。

+0

如果用户在Windows控制面板中更改了其首选文本大小,则会导致文本被裁剪或用户的首选文本大小被忽略。 – 2017-01-23 12:04:32

1

请记住,由于提到的许多问题都与字体大小有关,因此与字体系列和大小保持一致非常重要。 这意味着将字体设置为基本窗体或基本用户控件(如果有的话),并让控件继承该设置。 我注意到,当我有一个UserControl里面的窗体,如果我选择控件并更改字体大小,一些项目调整大小,有些则没有。 我意识到,没有调整大小的项目的字体设置专门设置(over-ridden)。那时我才意识到这些财产以粗体显示时意味着什么。 因此,例如,如果您有一个标签,字体道具为粗体,表示有人对其进行了更改。 你应该清除所有这些设置的字体道具,以便他们从父级获取字体,在这种情况下是包含表单。 您可以简单地突出显示字体属性文本并删除或右键单击字体道具并选择清除。 这将删除设计器文件中的字体行,并允许控件从其父项继承该字体。这可能会跳回到微软Sans Serif,但如果你构建它会从其父母拿起字体 当然,你应该遵循适当的设计使用布局面板和锚和码头属性,但我发现,一般来说,如果你清除所有结束你会发现如果你从你的表单中选择用户控件并将自动缩放控制代码改为无,那么你将会有更好的运气 同样对于测试,如果你改变了userontrol的字体大小,那么它的所有控件应该调整大小(只要没有字体道具被覆盖) 只要表单使用合适的布局面板设计,所有内容在其他分辨率下都应该显示正常。 至少到目前为止,我已经工作。

+0

对不起,你似乎错过了我的答案。 Winforms中有一个** bug **,它完全阻止使用您描述的继承机制。如果要确保多行文本框和标签正确缩放,每个控件都需要自己的字体分配。 – 2016-03-16 14:28:19

+0

哎呀,很抱歉... 我经历过的唯一时间是更改字体时,它不会生效,直到我重新构建 除此之外,我不怀疑你是正确的,它发生在其他时间作为好。 我的文章的主要观点是提到寻找重叠的字体设置,因为如果有的话,父字体设置不会生效。 – billymac 2016-03-18 18:14:38

0

我也有这个问题。特别是LinkLabels显示的字体太大,AutoSize标签在某处结束。在第一个对话框(Main)上将AutoScaleMode更改为Dpi可以解决所有窗体的问题。谢谢你的提示。

-1

我的WinForms应用程序具有字体大小首选项,其中字体可以在主屏幕上设置为三个级别(8pt,10pt或12pt),并且应该传播到所有子表单。

我遇到的具体问题是不是自动调整大小的标签(通常用于多行标签)和多行文本框。

我找到的解决方案是与在InitializeComponent()在Designer.cs文件适用的控制添加以下行:

this.Label1.Font = this.Font; 

this.MultiLineTextbox.Font = this.Font; 

这似乎设置AutoScale正确。