如何实现编辑模式下自定义TextBox的文本垂直居中、字体一致及高/字号独立设置
问题
自定义TextboxCommon控件在非编辑模式下文本显示正常,但需实现以下需求:
- 编辑模式下文本垂直居中
- 编辑/非编辑模式字体一致,无文本重叠
- 控件高度与字号相互独立:设置高度不影响字号,设置字号不改变高度
解决方案
要解决这些问题,需修正默认绘制逻辑的冲突,同时调整编辑模式下的文本布局,具体修改如下:
消除文本重叠:禁用默认绘制
原代码中base.OnPaint(e)会触发系统默认的文本绘制,导致编辑模式下自定义文本与系统文本重叠。直接移除这行代码,完全由自定义逻辑绘制边框和文本。编辑模式垂直居中:调整内部边距
TextBox编辑模式下的输入区域有默认垂直边距,通过Windows API调整该边距,让输入文本与非编辑模式的绘制文本对齐。重写CreateParams,动态计算垂直边距并通过SendMessage设置。保持高度与字号独立
保留AutoSize = false,让控件高度由手动设置决定;同时通过OnSizeChanged和OnFontChanged触发控件句柄重建,确保尺寸或字体变化时边距重新计算,互不影响。
修改后完整代码
public partial class TextboxCommon : TextBox { public TextboxCommon() : base() { SetStyle(ControlStyles.UserPaint, true); AutoSize = false; BorderStyle = BorderStyle.None; TextAlign = HorizontalAlignment.Left; Font = new Font("Calibri light", 16, GraphicsUnit.Point); } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; // 启用多行样式确保边距设置生效 cp.Style |= 0x200; // 计算垂直居中所需的上下边距 int verticalPadding = (Height - Font.Height) / 2; // EM_SETMARGINS:高16位设置上下边距,低16位设置左右边距 SendMessage(Handle, 0xD3, (IntPtr)2, (IntPtr)(verticalPadding << 16 | 0)); return cp; } } [System.Runtime.InteropServices.DllImport("user32.dll")] private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam); protected override void OnPaint(PaintEventArgs e) { // 绘制红色边框 using Pen penBorder = new Pen(Color.Red, 1); Rectangle rectBorder = new Rectangle(e.ClipRectangle.X, e.ClipRectangle.Y, e.ClipRectangle.Width - 1, e.ClipRectangle.Height - 1); e.Graphics.DrawRectangle(penBorder, rectBorder); // 绘制垂直居中的紫色文本 using Brush brush = new SolidBrush(Color.Purple); StringFormat stringFormat = new StringFormat { LineAlignment = StringAlignment.Center, Alignment = StringAlignment.Near }; e.Graphics.DrawString(Text, this.Font, brush, rectBorder, stringFormat); } protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); // 尺寸变化时重建句柄,应用新的边距计算 RecreateHandle(); } protected override void OnFontChanged(EventArgs e) { base.OnFontChanged(e); // 字体变化时重建句柄,重新计算边距 RecreateHandle(); } }
关键细节说明
- 使用
using语句管理GDI对象:避免Pen和Brush的资源泄漏,这是WinForms自定义绘制的最佳实践。 RecreateHandle()的作用:当控件高度或字体变化时,强制重建控件句柄,确保新的边距设置立即生效,保证高度与字号的独立性。EM_SETMARGINS消息:通过Windows原生API直接调整TextBox的内部边距,是实现编辑模式文本垂直居中的可靠方式。
内容的提问来源于stack exchange,提问作者armadillo.mx
相关产品推荐
相关产品推荐

