【问题标题】:Changing font for richtextbox without losing formatting更改richtextbox的字体而不丢失格式
【发布时间】:2022-02-27 13:28:35
【问题描述】:

如何在不丢失格式的情况下更改richtextbox所有内容的字体?

我正在尝试使用

rtb.SelectAll();
rtb.SelectionFont = new Font(fontName,...);

但是字体构造器除了字体类型之外还必须采用字体样式(粗体、斜体、...)或字体大小。 所以使用它会改变richtextbox所有内容的样式/大小。

当然,这同样适用于富文本框中的任何选择。

【问题讨论】:

标签: c# fonts formatting richtextbox


【解决方案1】:

这是我过去使用过的 RichTextBox。它是从 Stack Overflow 和整个互联网上的代码拼接在一起的:

public class RichBox : RichTextBox {
  private const UInt32 CFM_BOLD = 0x00000001;
  private const UInt32 CFM_ITALIC = 0x00000002;
  private const UInt32 CFM_UNDERLINE = 0x00000004;
  private const UInt32 CFM_STRIKE = 0x00000008;
  private const UInt32 CFM_FACE = 0x20000000;
  private const UInt32 CFM_SIZE = 0x80000000;

  private const int WM_PAINT = 0xF;
  private const int WM_SETREDRAW = 0xB;
  private const int WM_USER = 0x400;

  private const int EM_SETCHARFORMAT = (WM_USER + 68);
  private const int SCF_SELECTION = 0x0001;
  private const int EM_GETEVENTMASK = WM_USER + 59;
  private const int EM_SETEVENTMASK = WM_USER + 69;
  private const int EM_GETSCROLLPOS = WM_USER + 221;
  private const int EM_SETSCROLLPOS = WM_USER + 222;

  [StructLayout(LayoutKind.Sequential)]
  private struct CHARFORMAT {
    public int cbSize;
    public uint dwMask;
    public uint dwEffects;
    public int yHeight;
    public int yOffset;
    public int crTextColor;
    public byte bCharSet;
    public byte bPitchAndFamily;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
    public char[] szFaceName;
    public short wWeight;
    public short sSpacing;
    public int crBackColor;
    public int LCID;
    public uint dwReserved;
    public short sStyle;
    public short wKerning;
    public byte bUnderlineType;
    public byte bAnimation;
    public byte bRevAuthor;
  }

  [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
  private static extern IntPtr LoadLibrary(string lpFileName);

  [DllImport("user32", CharSet = CharSet.Auto)]
  private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, ref CHARFORMAT lParam);

  [DllImport("user32.dll")]
  private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);

  [DllImport("user32.dll")]
  private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);

  private bool frozen = false;
  private Point lastScroll = Point.Empty;
  private IntPtr lastEvent = IntPtr.Zero;
  private int lastIndex = 0;
  private int lastWidth = 0;

  protected override CreateParams CreateParams {
    get {
      var cp = base.CreateParams;
      if (LoadLibrary("msftedit.dll") != IntPtr.Zero) {
        cp.ClassName = "RICHEDIT50W";
      }
      return cp;
    }
  }

  [Browsable(false)]
  [DefaultValue(typeof(bool), "False")]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public bool FreezeDrawing {
    get { return frozen; }
    set {
      if (value != frozen) {
        frozen = value;
        if (frozen) {
          this.SuspendLayout();
          SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
          SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref lastScroll);
          lastEvent = SendMessage(this.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
          lastIndex = this.SelectionStart;
          lastWidth = this.SelectionLength;
        } else {
          this.Select(lastIndex, lastWidth);
          SendMessage(this.Handle, EM_SETEVENTMASK, 0, lastEvent);
          SendMessage(this.Handle, EM_SETSCROLLPOS, 0, ref lastScroll);
          SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
          this.Invalidate();
          this.ResumeLayout();
        }
      }
    }
  }

  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public Font CurrentFont {
    get {
      Font result = this.Font;
      if (this.SelectionLength == 0) {
        result = SelectionFont;
      } else {
        using (RichBox rb = new RichBox()) {
          rb.FreezeDrawing = true;
          rb.SelectAll();
          rb.SelectedRtf = this.SelectedRtf;
          rb.Select(0, 1);
          result = rb.SelectionFont;
        }
      }
      return result;
    }
  }

  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public string SelectionFontName {
    get { return CurrentFont.FontFamily.Name; }
    set {
      CHARFORMAT cf = new CHARFORMAT();
      cf.cbSize = Marshal.SizeOf(cf);
      cf.szFaceName = new char[32];
      cf.dwMask = CFM_FACE;
      value.CopyTo(0, cf.szFaceName, 0, Math.Min(31, value.Length));
      IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
      Marshal.StructureToPtr(cf, lParam, false);
      SendMessage(this.Handle, EM_SETCHARFORMAT, SCF_SELECTION, lParam);
    }
  }

  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public float SelectionFontSize {
    get { return CurrentFont.Size; }
    set {
      CHARFORMAT cf = new CHARFORMAT();
      cf.cbSize = Marshal.SizeOf(cf);
      cf.dwMask = CFM_SIZE;
      cf.yHeight = Convert.ToInt32(value * 20);
      IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
      Marshal.StructureToPtr(cf, lParam, false);
      SendMessage(this.Handle, EM_SETCHARFORMAT, SCF_SELECTION, lParam);
    }
  }

  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public bool SelectionBold {
    get { return CurrentFont.Bold; }
    set {
      CHARFORMAT cf = new CHARFORMAT();
      cf.cbSize = Marshal.SizeOf(cf);
      cf.dwMask = CFM_BOLD;
      cf.dwEffects = value ? CFM_BOLD : 0;
      IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
      Marshal.StructureToPtr(cf, lParam, false);
      SendMessage(this.Handle, EM_SETCHARFORMAT, SCF_SELECTION, lParam);
    }
  }

  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public bool SelectionItalic {
    get { return CurrentFont.Italic; }
    set {
      CHARFORMAT cf = new CHARFORMAT();
      cf.cbSize = Marshal.SizeOf(cf);
      cf.dwMask = CFM_ITALIC;
      cf.dwEffects = value ? CFM_ITALIC : 0;
      IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
      Marshal.StructureToPtr(cf, lParam, false);
      SendMessage(this.Handle, EM_SETCHARFORMAT, SCF_SELECTION, lParam);
    }
  }

  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public bool SelectionStrikeout {
    get { return CurrentFont.Strikeout; }
    set {
      CHARFORMAT cf = new CHARFORMAT();
      cf.cbSize = Marshal.SizeOf(cf);
      cf.dwMask = CFM_STRIKE;
      cf.dwEffects = value ? CFM_STRIKE : 0;
      IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
      Marshal.StructureToPtr(cf, lParam, false);
      SendMessage(this.Handle, EM_SETCHARFORMAT, SCF_SELECTION, lParam);
    }
  }

  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  public bool SelectionUnderline {
    get { return CurrentFont.Underline; }
    set {
      CHARFORMAT cf = new CHARFORMAT();
      cf.cbSize = Marshal.SizeOf(cf);
      cf.dwMask = CFM_UNDERLINE;
      cf.dwEffects = value ? CFM_UNDERLINE : 0;
      IntPtr lParam = Marshal.AllocCoTaskMem(Marshal.SizeOf(cf));
      Marshal.StructureToPtr(cf, lParam, false);
      SendMessage(this.Handle, EM_SETCHARFORMAT, SCF_SELECTION, lParam);
    }
  }
}

它添加了新的属性,例如 SelectionBold、SelectionItalic 等,您可以在其中应用属性而不会丢失文本的其他格式。

【讨论】:

  • 嗨 LarsTech,有时当我为包含粗体的大型选择更改字体时,粗体会丢失。当我单击一次 ctrl+Z 时,会恢复粗体。您知道为什么会发生这种情况吗?谢谢
  • @Jerry 如果您要更改SelectionFont 属性,那么是的,您是在告诉文档用新字体替换所有字体属性。要更改字体但保留属性,请尝试改用SelectionFontNameSelectionFontSize 属性。另外,Ctrl-Z 是撤销功能。
  • 谢谢,这就是问题所在。我忘了更新一个函数以使用SelectionFontName 而不是SelectionFont
  • @AlexJolig AutoScaleMode 是表单属性,而不是 RichTextBox 属性。删除该行。
  • 这比一次更改一个字符的字体要快得多。使用此解决方案,我需要 12 毫秒才能完成过去需要 4 秒以上的工作。
【解决方案2】:

您可以使用现有的 Richtextbox 字体属性传递新字体名称,同时保持其他值不变。要仅更改所选文本的字体名称,您需要执行以下操作:

if (rtb.SelectionFont !=null)
    rtb.SelectionFont = new Font(fontName, rtb.SelectionFont.Size, rtb.SelectionFont.Style);

请注意,上面的代码只有在所有选定的文本具有相同的格式(字体大小、样式等)时才有效。这是通过首先检查 SelectionFont 属性来检测的,如果选择包含混合样式,它将为 null。

现在要更改richtextbox所有内容的字体名称,同时保持其他格式不变,您需要遍历richtextbox的所有字符并逐个应用字体名称。

for (int i = 0; i < rtb.TextLength; i++)
{
    rtb.Select(i, 1);
    rtb.SelectionFont = new Font(fontName, rtb.SelectionFont.Size, rtb.SelectionFont.Style);
}

【讨论】:

    【解决方案3】:

    您可以为所需的任何参数传入新值,并使用rtb 属性来保留其他值。例如,如果您想更改font family 但想保留font size,您可以这样做:

    rtb.SelectionFont = new Font(fontName, rtb.Font.Size);
    

    这会将SelectionFont 系列更改为fontName,但会保留字体大小。对于其他重载,您可以遵循相同的模式。

    【讨论】:

    • 字体大小不同是什么意思?解释一下你到底想要达到什么目标,然后也许我们可以弄清楚。
    • 不同的文字,不同的字体大小。无论如何,即使您的回答也会导致字体样式发生变化。
    【解决方案4】:
    Private Sub changeFont(ByVal fontz As FontStyle, getStr As RichTextBox)
       Dim currentFont As System.Drawing.Font = txt.SelectionFont
       Dim newFontStyle As System.Drawing.FontStyle
       newFontStyle = fontz
       getStr.SelectionFont = New Font(currentFont.FontFamily, currentFont.Size, newFontStyle)
    End Sub
    

    这将更改所选文本的字体属性。
    示例:

    changeFont(FontStyle.Italic, [textbox_name])
    

    【讨论】:

      【解决方案5】:

      在不丢失格式的情况下更改richtextbox的字体

      private void Change_RichTextBox_FontName(string fontName )
      {
      
              if (richTextBox1.TextLength ==0)
              {
                  return;
              }
      
              richTextBox1.Select(0, 1);
              var lastTextColor = richTextBox1.SelectionColor;
              var lastFontStyle  = richTextBox1.SelectionFont.Style;
              var lastFontSize = richTextBox1.SelectionFont.Size;
              var lastSelectionStart = 0;
              for (int i=1; i < richTextBox1.TextLength;i++)
              {
                  richTextBox1.Select(i, 1);
      
                  var selColor = richTextBox1.SelectionColor;
                  var selStyle = richTextBox1.SelectionFont.Style;
                  var selSize = richTextBox1.SelectionFont.Size;
      
                  if (selColor != lastTextColor ||
                      selStyle != lastFontStyle ||
                      selSize !=  lastFontSize ||
                       i== richTextBox1.TextLength-1)
                  {
                      richTextBox1.Select(lastSelectionStart, i - lastSelectionStart);
                      richTextBox1.SelectionColor = lastTextColor;
                      richTextBox1.SelectionFont = 
                          new Font(fontName, lastFontSize, lastFontStyle);
                      
                      lastTextColor = selColor;
                      lastFontStyle = selStyle;
                      lastFontSize =  selSize;
                      lastSelectionStart = i;
                  }
              }
          }
      

      【讨论】:

      • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-25
      • 1970-01-01
      • 1970-01-01
      • 2017-12-07
      • 1970-01-01
      • 2013-11-07
      相关资源
      最近更新 更多