WinForm RichTextBox方框绘制字符字体被替换问题求助
问题
在Windows窗体的RichTextBox控件中,已将字体设置为Consolas等宽字体,大部分内容可正常渲染,但加载或设置包含**方框绘制字符(Box-drawing characters)**的内容时,这类字符会被自动替换为Segoe UI Symbol字体,破坏了等宽排版效果。
示例代码:
private void InitializeComponent() { // ... this.richTextBox1 = new System.Windows.Forms.RichTextBox(); this.richTextBox1.Font = new System.Drawing.Font("Consolas", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); this.richTextBox1.Location = new System.Drawing.Point(45, 34); this.richTextBox1.Name = "richTextBox1"; this.richTextBox1.Size = new System.Drawing.Size(533, 318); this.richTextBox1.TabIndex = 0; this.richTextBox1.Text = "╔════════════════════════════════════════════════╗\n" + "║ This is a test ║\n" + "╚════════════════════════════════════════════════╝"; // ... }
将内容复制到Microsoft Word后可观察到:仅 This is a test 部分使用Consolas字体,其余方框绘制字符均被替换为Segoe UI Symbol字体。已确认Consolas字体本身支持这些方框绘制字符,需要阻止RichTextBox的自动字体替换行为。
解决方案
方法1:手动构造RTF格式内容强制指定字体
RichTextBox底层依赖RTF渲染,直接设置Text属性时系统会触发自动字体替换逻辑。可以构造完整的RTF内容,强制所有字符使用Consolas字体:
// 构造RTF内容,\fs24对应12号字体(RTF字号为点数的2倍) string rtfContent = @"{\rtf1\ansi\deff0{\fonttbl{\f0 Consolas;}} \f0\fs24 ╔════════════════════════════════════════════════╗ ║ This is a test ║ ╚════════════════════════════════════════════════╝ }"; richTextBox1.Rtf = rtfContent;
方法2:自定义RichTextBox拦截字体替换消息
通过重写控件的消息处理逻辑,拦截系统自动替换字体的操作,创建自定义控件:
using System.Runtime.InteropServices; using System.Windows.Forms; public class FixedFontRichTextBox : RichTextBox { protected override void WndProc(ref Message m) { const int WM_CHARFORMAT = 0x0030; if (m.Msg == WM_CHARFORMAT) { // 强制设置全局字体为控件指定的Consolas var cf = new CHARFORMAT2(); cf.cbSize = (uint)Marshal.SizeOf(cf); cf.dwMask = CFM_FACE | CFM_SIZE; cf.szFaceName = this.Font.Name; cf.yHeight = (int)(this.Font.Size * 20); // RTF字号单位为1/20点 Marshal.StructureToPtr(cf, m.LParam, false); } base.WndProc(ref m); } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] private struct CHARFORMAT2 { public uint cbSize; public uint dwMask; public uint dwEffects; public int yHeight; public int yOffset; public int crTextColor; public byte bCharSet; public byte bPitchAndFamily; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szFaceName; } private const uint CFM_FACE = 0x00000020; private const uint CFM_SIZE = 0x00000080; }
使用时将窗体中的RichTextBox替换为该自定义控件即可。
方法3:将纯文本转换为带字体指定的RTF
通过工具方法将普通文本包装为指定字体的RTF内容,再设置给控件的Rtf属性:
public static string TextToRtf(string text, Font font) { // 转义RTF特殊字符,包装为指定字体的RTF结构 string escapedText = text.Replace("\\", "\\\\").Replace("{", "\\{").Replace("}", "\\}"); return $"{{\\rtf1\\ansi\\deff0{{\\fonttbl{{\\f0 {font.Name};}}}}\\f0\\fs{font.Size * 20} {escapedText}}}"; } // 使用示例 richTextBox1.Rtf = TextToRtf(richTextBox1.Text, richTextBox1.Font);
内容的提问来源于stack exchange,提问作者Martin Prikryl
相关产品推荐
相关产品推荐

