You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现编辑模式下自定义TextBox的文本垂直居中、字体一致及高/字号独立设置

问题

自定义TextboxCommon控件在非编辑模式下文本显示正常,但需实现以下需求:

  • 编辑模式下文本垂直居中
  • 编辑/非编辑模式字体一致,无文本重叠
  • 控件高度与字号相互独立:设置高度不影响字号,设置字号不改变高度
解决方案

要解决这些问题,需修正默认绘制逻辑的冲突,同时调整编辑模式下的文本布局,具体修改如下:

  1. 消除文本重叠:禁用默认绘制
    原代码中base.OnPaint(e)会触发系统默认的文本绘制,导致编辑模式下自定义文本与系统文本重叠。直接移除这行代码,完全由自定义逻辑绘制边框和文本。

  2. 编辑模式垂直居中:调整内部边距
    TextBox编辑模式下的输入区域有默认垂直边距,通过Windows API调整该边距,让输入文本与非编辑模式的绘制文本对齐。重写CreateParams,动态计算垂直边距并通过SendMessage设置。

  3. 保持高度与字号独立
    保留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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 05:07:17