切换启用时文本框的文本略有移动:字体和字体大小更改
Posted
技术标签:
【中文标题】切换启用时文本框的文本略有移动:字体和字体大小更改【英文标题】:TextBox's Text is moving slightly when toggling Enabled: Font and Font size changes 【发布时间】:2021-09-23 05:14:17 【问题描述】:在我的应用程序中,我有自定义文本框控件。当我更改 Enabled
属性时,它的文本似乎在移动。
我不明白这是什么原因。
我将更改 TextAlign
、AutoSize
、Enabled
和 Font
属性
我尝试使用TextRenderer.DrawText()
:它似乎解决了一些问题,但是当我更改为某些字体和字体大小时,文本再次移动(例如,设置 MS ゴシック,10pt)。
我已经搜索了该网站并阅读了以下内容,但似乎没有正确理解:
Using Graphics.DrawString to Simulate TextBox rendering
How do I use DrawString without trimming?
Graphics.DrawString vs TextRenderer.DrawText?Which can Deliver Better Quality
以下是一些截图:
MS ゴシック、10pt 和 TextAlign Center 和 e.Graphics.DrawString
↓↓ Enabled ↓↓
↓↓ Disabled ↓↓
comparison
MS ゴシック、10pt 和 TextAlign Center 和 TextRenderer.DrawText
↓↓ Enabled ↓↓
↓↓ Disabled ↓↓
comparison (text seems to be slightly elongated when disabled)
我的代码的原始帖子 https://devlights.hatenablog.com/entry/20070523/p1
这是我的自定义控件代码:
using System.Drawing;
using System.Windows.Forms;
public partial class CustomEnabledStateTextBox : TextBox
public CustomEnabledStateTextBox()
InitializeComponent();
AutoSize = false;
public override bool AutoSize
get return base.AutoSize;
set base.AutoSize = value;
protected override void OnEnabledChanged(EventArgs e)
this.SetStyle(ControlStyles.UserPaint, !this.Enabled);
this.Invalidate();
base.OnEnabledChanged(e);
protected override void OnPaint(PaintEventArgs e)
base.OnPaint(e);
using (StringFormat sf = new StringFormat())
if (this.TextAlign == HorizontalAlignment.Center)
sf.Alignment = StringAlignment.Center;
else if (this.TextAlign == HorizontalAlignment.Left)
sf.Alignment = StringAlignment.Near;
else
sf.Alignment = StringAlignment.Far;
using (SolidBrush brush = new SolidBrush(ForeColor))
//MS UI Gothic, 8pt --> not OK
//MS UI Gothic, 9pt --> OK
//MS UI Gothic, 10pt --> OK
//MS UI Gothic, 11pt --> OK
//MS UI Gothic, 12pt --> not OK
e.Graphics.DrawString(
base.Text, base.Font, brush, new Rectangle(-1, 1, base.Width, base.Height), sf);
//MS ゴシック, 8pt --> not OK
//MS ゴシック, 9pt --> not OK
//MS ゴシック, 10pt --> not OK
//MS ゴシック, 12pt --> not OK
//e.Graphics.DrawString(
// base.Text, base.Font, brush, new Rectangle(-1, 1, base.Width, base.Height), sf);
//MS ゴシック, 10pt --> not OK
//TextRenderer.DrawText(e.Graphics, Text, Font, new Rectangle(0, 0, Width, Height), ForeColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.NoPadding | TextFormatFlags.Internal);
if (this.BorderStyle == BorderStyle.FixedSingle)
e.Graphics.DrawRectangle(new Pen(Color.Black), 0, 0, this.Width - 1, this.Height - 1);
测试表格:
public partial class Form1 : Form
public Form1()
InitializeComponent();
customEnabledStateTextBox1.Text = "2021/04/04";
customEnabledStateTextBox1.Size = new Size(88, 20);
customEnabledStateTextBox1.BorderStyle = BorderStyle.None;
customEnabledStateTextBox1.TextAlign = HorizontalAlignment.Center;
private void button1_Click(object sender, EventArgs e)
customEnabledStateTextBox1.Enabled = true;
private void button2_Click(object sender, EventArgs e)
customEnabledStateTextBox1.Enabled = false;
更新 1
我已根据 Jimi 提供的答案更改了我的代码 并对其进行了测试并解决了一些问题,但是当我使用时问题仍然存在 MS ゴシック, 10pt 发现在 MS UI Gothic, 10pt 和 MS ゴシック, 10pt 的情况下,文本略微向下移动。我的应用程序使用 MS ゴシック 7pt~12pt。所以我必须正确显示 10pt。 我还没有测试过其他字体。 请帮忙。
对不起,我之前没有提供 .Net 框架 我正在使用
.NET Framework 3.5
BorderStyle None
测试用例
MS UI Gothic, 8pt-- > OK
MS UI Gothic, 9pt-- > OK
MS UI Gothic, 10pt-- > not OK
MS UI Gothic, 11pt-- > OK
MS UI Gothic, 12pt-- > OK
MS ゴシック, 8pt-- > OK
MS ゴシック, 9pt-- > OK
MS ゴシック, 10pt-- > not OK
MS ゴシック, 12pt-- > OK
这里是截图
MS ゴシック, 10pt And TextAlign Center and BorderStyle None andTextRenderer.DrawText
MS UI Gothic、10pt 和 TextAlign Center 和 BorderStyle None 和 TextRenderer.DrawText
更新代码如下: 我在 .Net Framework 3.5 和 4.8 中都对其进行了测试
CustomEnabledStateTextBox:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFormTest1
public partial class CustomEnabledStateTextBox : TextBox
public override bool AutoSize
get return base.AutoSize;
set base.AutoSize = value;
public CustomEnabledStateTextBox()
InitializeComponent();
AutoSize = false;
protected override void OnEnabledChanged(EventArgs e)
//>>>Change 1
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, !Enabled);
UpdateStyles();
//>>>Change 1
base.OnEnabledChanged(e);
//>>>Change 1
protected override void OnBorderStyleChanged(EventArgs e)
base.OnBorderStyleChanged(e);
if (BorderStyle == BorderStyle.FixedSingle)
BorderStyle = BorderStyle.Fixed3D;
//>>>Change 1
protected override void OnPaint(PaintEventArgs e)
using (StringFormat sf = new StringFormat())
if (this.TextAlign == HorizontalAlignment.Center)
sf.Alignment = StringAlignment.Center;
else if (this.TextAlign == HorizontalAlignment.Left)
sf.Alignment = StringAlignment.Near;
else
sf.Alignment = StringAlignment.Far;
//>>>Change 1
var rect = ClientRectangle;
if (BorderStyle != BorderStyle.None) rect.Inflate(-1, -1);
var alignment = TextAlign == HorizontalAlignment.Left
? TextFormatFlags.Left : (TextFormatFlags)((int)TextAlign ^ 3);
var flags = TextFormatFlags.TextBoxControl | TextFormatFlags.NoPadding | alignment;
//>>>Change 1
using (SolidBrush brush = new SolidBrush(ForeColor))
//MS UI Gothic, 8pt --> not OK
//MS UI Gothic, 9pt --> OK
//MS UI Gothic, 10pt --> OK
//MS UI Gothic, 11pt --> OK
//MS UI Gothic, 12pt --> not OK
//e.Graphics.DrawString(
// base.Text, base.Font, brush, new Rectangle(-1, 1, base.Width, base.Height), sf);
//MS ゴシック, 8pt --> not OK
//MS ゴシック, 9pt --> not OK
//MS ゴシック, 10pt --> not OK
//MS ゴシック, 12pt --> not OK
//e.Graphics.DrawString(
// base.Text, base.Font, brush, new Rectangle(-1, 1, base.Width, base.Height), sf);
//MS ゴシック, 10pt --> not OK
//TextRenderer.DrawText(e.Graphics, Text, Font, new Rectangle(0, 0, Width, Height), ForeColor, TextFormatFlags.HorizontalCenter | TextFormatFlags.NoPadding | TextFormatFlags.Internal);
//TextRenderer.DrawText(e.Graphics, Text, Font, new Rectangle(0, 0, Width, Height), ForeColor, flags);
//>>>Change 1
//MS UI Gothic, 8pt --> OK
//MS UI Gothic, 9pt --> OK
//MS UI Gothic, 10pt --> not OK
//MS UI Gothic, 11pt --> OK
//MS UI Gothic, 12pt --> OK
//MS ゴシック, 8pt --> OK
//MS ゴシック, 9pt --> OK
//MS ゴシック, 10pt --> not OK
//MS ゴシック, 12pt --> OK
TextRenderer.DrawText(e.Graphics, Text, Font, rect, ForeColor, flags);
//>>>Change 1
if (this.BorderStyle == BorderStyle.FixedSingle)
e.Graphics.DrawRectangle(new Pen(Color.Black), 0, 0, this.Width - 1, this.Height - 1);
//>>>Change 1
base.OnPaint(e);
//>>>Change 1
CustomEnabledStateTextBoxSO:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFormTest1
public partial class CustomEnabledStateTextBoxSO : TextBox
public override bool AutoSize
get return base.AutoSize;
set base.AutoSize = value;
public CustomEnabledStateTextBoxSO()
InitializeComponent();
AutoSize = false;
protected override void OnEnabledChanged(EventArgs e)
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, !Enabled);
UpdateStyles();
base.OnEnabledChanged(e);
protected override void OnBorderStyleChanged(EventArgs e)
base.OnBorderStyleChanged(e);
if (BorderStyle == BorderStyle.FixedSingle)
BorderStyle = BorderStyle.Fixed3D;
protected override void OnPaint(PaintEventArgs e)
var rect = ClientRectangle;
if (BorderStyle != BorderStyle.None) rect.Inflate(-1, -1);
var alignment = TextAlign == HorizontalAlignment.Left
? TextFormatFlags.Left : (TextFormatFlags)((int)TextAlign ^ 3);
var flags = TextFormatFlags.TextBoxControl | TextFormatFlags.NoPadding | alignment;
//MS UI Gothic, 8pt-- > OK
//MS UI Gothic, 9pt-- > OK
//MS UI Gothic, 10pt-- > not OK
//MS UI Gothic, 11pt-- > OK
//MS UI Gothic, 12pt-- > OK
//MS ゴシック, 8pt-- > OK
//MS ゴシック, 9pt-- > OK
//MS ゴシック, 10pt-- > not OK
//MS ゴシック, 12pt-- > OK
TextRenderer.DrawText(e.Graphics, Text, Font, rect, ForeColor, flags);
base.OnPaint(e);
测试表格:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
//using System.Threading.Tasks;
using System.Windows.Forms;
namespace WinFormTest1
public partial class Form1 : Form
public Form1()
InitializeComponent();
//Left Side
customEnabledStateTextBox1.Text = "2021/04/04";
customEnabledStateTextBox1.Size = new Size(88, 20); //size will change if i set Autosize true
customEnabledStateTextBox1.BorderStyle = BorderStyle.None;
customEnabledStateTextBox1.TextAlign = HorizontalAlignment.Center;
//Right Side
customEnabledStateTextBoxSO1.Text = "2021/04/04";
customEnabledStateTextBoxSO1.Size = new Size(88, 20); //size will change if i set Autosize true
customEnabledStateTextBoxSO1.BorderStyle = BorderStyle.None;
customEnabledStateTextBoxSO1.TextAlign = HorizontalAlignment.Center;
private void button1_Click(object sender, EventArgs e)
customEnabledStateTextBox1.Enabled = true;
customEnabledStateTextBoxSO1.Enabled = true;
private void button2_Click(object sender, EventArgs e)
customEnabledStateTextBox1.Enabled = false;
customEnabledStateTextBoxSO1.Enabled = false;
【问题讨论】:
【参考方案1】:对文本渲染的一些更改应该可以让您接近您的预期。
使用TextRenderer绘制文字 将TextFormatFlags.TextBoxControl
和TextFormatFlags.NoPadding
添加到TextRenderer.DrawText()
中使用的TextFormatFlags(请参阅有关这两个的文档)
重写OnBorderStyleChanged()
以在自定义绘制控件时将FixedSingle
样式替换为Fixed3D
。这就是基类 (TextBoxBase) 的作用,否则您将获得缩小 Win32 控件客户端区域的默认内部边框。
当BorderStyle = BorderStyle.Fixed3D
时,将控件的ClientRectangle 膨胀-1
像素。
我在SetStyle()
调用之后添加了UpdateStyles():这会强制使用新样式并导致控件重新绘制自身。
请注意,设置不支持设置控件文本时使用的所有 CodePoint(简化:文本中的 Unicode 字符)的字体可能会导致字体回退。 在实践中,系统将选择一个映射的代理字体来替换控件的字体。这发生在透明且没有通知。 不同的图形渲染器在类似情况下的行为方式可能不同。
在此处查看注释:How can a Label control display Japanese characters properly when the Font used doesn't support this language?
RichTextBox 控件有些不同(.Net 基类相同,但 Win32 控件完全不同):Some Alt keys changes my RichTextBox font
此外,最近,所有亚洲字体渲染和 UI 呈现都进行了修改,以更好地处理其特性。所以使用中的 .Net 版本也可以改变行为。
这里的代码是用.Net Framework 4.8
测试的。
public partial class CustomEnabledStateTextBox : TextBox
public CustomEnabledStateTextBox() => this.AutoSize = false;
protected override void OnEnabledChanged(EventArgs e)
SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, !Enabled);
UpdateStyles();
base.OnEnabledChanged(e);
protected override void OnBorderStyleChanged(EventArgs e)
base.OnBorderStyleChanged(e);
if (BorderStyle == BorderStyle.FixedSingle) BorderStyle = BorderStyle.Fixed3D;
private TextFormatFlags flags = TextFormatFlags.TextBoxControl |
TextFormatFlags.NoPadding;
protected override void OnPaint(PaintEventArgs e)
var rect = ClientRectangle;
if (BorderStyle != BorderStyle.None) rect.Inflate(-1, -1);
var alignment = TextAlign == HorizontalAlignment.Left
? TextFormatFlags.Left : (TextFormatFlags)((int)TextAlign^ 3);
flags |= alignment;
TextRenderer.DrawText(e.Graphics, Text, Font, rect, ForeColor, flags);
base.OnPaint(e);
【讨论】:
感谢您的回答。它解决了一些问题,但 MS ゴシック,10pt 问题仍然存在。我已经更新了我的帖子。 MS UI Gothic 是我的语言(en-US)中的日语后备字体之一:它通常是隐藏的,仅用作后备字体代理,如此处所述。我已经测试过这个字体,它和我测试过的所有其他字体完全一样(是的,我已经测试过 10pt)。如前所述,您需要 .Net Framework 4.8 或 .Net Core 3.1 或 .Net 5 才能进行正确测试。 是的,我已经在 .NetFramework 4.8 中安装并测试过了。我也更改了 AutoScaleMode。问题仍然存在于我的环境中。虽然我的显示语言是日语。我也检查了注册表。它有 MS UI 哥特式。 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink 也许我应该避免 10pt 。谢谢吉米 是的,当然,如果您的系统语言是日语,那么 MS UI Gothic 可以设置为 visible(不隐藏,因为在我的中用作备用字体)。 -- 您应该允许使用 10pt。我不确定你为什么对那个尺寸有问题,因为如前所述,我已经对其进行了测试(取消隐藏字体)并且 10pt 与其他尺寸具有相同的结果(10pt 实际上是 9.75pt)。也许让我知道这段代码在什么系统和版本中测试过,这样我就可以尝试复制这个问题。 我将 MS ゴシック, 10pt 更改为新字体(control.FontFamily, 10.2f),问题就解决了。谢谢。以上是关于切换启用时文本框的文本略有移动:字体和字体大小更改的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 css 更改一个选择框选项文本(select2)的字体大小?