如何在C#中的Richtextbox中更改多个大小的字体?

3

我有一个RichTextBox,想让它像WordPad一样工作。我的问题在于,例如,如果我使用Calibri字体键入“123”,然后使用Arial字体键入“456”,并且我想更改2345的大小,它不会让我这样做,因为它们有两种不同的字体类型。这就是我遇到的问题:

private void combo_sizes_TextChanged(object sender, EventArgs e)
{
    if (rtb.SelectionFont == null)
    {
        rtb.SelectionFont = new Font(combo_fonts.Text, Convert.ToInt16(combo_sizes.Text));
    }
    rtb.SelectionFont = new Font(rtb.SelectionFont.FontFamily, Convert.ToInt16(combo_sizes.Text));
}

我知道在rtb中选择的文本包含多种字体时,SelectionFont等于null,因此在这种情况下,我已经从两个组合框中获取了所选文本的大小和字体,但我希望在不丢失原始字体的情况下更改大小。是否有解决方案?

谢谢

3个回答

1
将您的所选文本分解为字符。获取每个字符的字体,并更改其大小。

我忘了说我是一个基础程序员,所以我完全不明白你的答案。请问你能告诉我如何做吗? - Carlos Chévez
1
没有人天生就是程序员。:) 随着你的练习,你会变得越来越高效。我会尽可能简单地更新我的答案。 - Shaharyar

0

我也有同样的需求,但是我没有找到最好的解决方案...所以,这里提供一个丑陋的解决方案。

private void UglyChangeFontSize(RichTextBox rtb, float newSize = -1f, FontFamily fontFamily = null) {
    if (rtb.SelectionFont != null) {

        if (newSize < 0) newSize = rtb.SelectionFont.Size;
        if (fontFamily == null) fontFamily = rtb.SelectionFont.FontFamily;

        rtb.SelectionFont = new Font(fontFamily, newSize, rtb.SelectionFont.Style);
    }
    else {
        // Backup Selection
        var sel = rtb.SelectionStart;
        var selLen = rtb.SelectionLength;

        // Change, char by char
        for (int k = 0; k < selLen; k++) {
            rtb.Select(sel + k, 1);

            if (newSize < 0) newSize = rtb.SelectionFont.Size;
            var ff = fontFamily ?? rtb.SelectionFont.FontFamily;

            rtb.SelectionFont = new Font(fontFamily, newSize, rtb.SelectionFont.Style);
        }

        // Restore Selection
        rtb.SelectionStart = sel;
        rtb.SelectionLength = selLen;
    }
}

改进版

这是一个更好的版本,它包括:

  1. 禁用 RichTextBox 绘制(更改字体时);
  2. 防止“逐字符修改”进入撤消/重做堆栈;
  3. 执行更改时显示 WaitCursor。

要求

  1. External.cs
  2. RichOLE.cs
  3. (可选) RicherTextBox -- 我的代码是围绕这个构建的,它是构建类似 WordPad 项目的不错起点

代码

RichTextBox myRichTextBox = new RichTextBox();
RichOLE mRichOle = new RichOLE(myRichTextBox);

...

private void UglyChangeFontSize(RichTextBox rtb, float newSize = -1f, FontFamily fontFamily = null) {
    if (rtb.SelectionFont != null) {

        if (newSize < 0) newSize = rtb.SelectionFont.Size;
        if (fontFamily == null) fontFamily = rtb.SelectionFont.FontFamily;

        rtb.SelectionFont = new Font(fontFamily, newSize, rtb.SelectionFont.Style);
    }
    else {
        Cursor = Cursors.WaitCursor;

        // Hide the modifications from the user
        External.LockWindowAndKeepScrollPosition(rtb, () => 
        {
            // Backup Selection
            var sel = rtb.SelectionStart;
            var selLen = rtb.SelectionLength;

            // Disable UNDO for this "in pieces modifications" [START]
            rtb.SelectedRtf = rtb.SelectedRtf; // Required to allow Undo
            //mFontLockEvents = true; // RicherTextBox
            mRichOle.EnableUndo(false);
            // Disable UNDO for this "in pieces modifications" [END]

            // Change, char by char
            for (int k = 0; k < selLen; k++) {
                rtb.Select(sel + k, 1);

                // again, ugly... buuut we have Branch Prediction (google it)
                if (newSize < 0) newSize = rtb.SelectionFont.Size;
                var ff = fontFamily ?? rtb.SelectionFont.FontFamily;

                rtb.SelectionFont = new Font(fontFamily, newSize, rtb.SelectionFont.Style);
            }

            // Disable UNDO for this "in pieces modifications" [START]
            //mFontLockEvents = false; // RicherTextBox
            mRichOle.EnableUndo(true);
            // Disable UNDO for this "in pieces modifications" [END]

            // Restore Selection
            rtb.SelectionStart = sel;
            rtb.SelectionLength = selLen;
        });
        Cursor = Cursors.Default;
    }
}

0

RichTextBox(RTB)中有两种内置字体:

  • Font 是任何输入后将使用的字体。因此,如果您想切换到另一种字体,则应设置此字体
  • SelectionFont 是当前选择的字体。这将随着选择而改变,但也用于设置已输入文本的一部分的字体。

但是,在同一时间和位置只能有其中一种字体。如果要切换回标准字体,则需要在某个地方保留标准字体。

或者,您可以将使用的所有字体存储在列表中,并在组合框中提供它们。

还请注意:

  • 输入文本后的所有格式都必须通过选择一部分然后更改该选择的属性来完成:字体、颜色、样式等。
  • 在任何文本的任何部分以任何方式进行格式化后,您都不能直接在代码中更改文本,而只能使用AppendText、Copy、Cut、Paste或其他方式,否则您将破坏格式!

您的代码可能像这样工作:

public Form1()
{
    InitializeComponent();

    lastSelectionFont = rtb.SelectionFont;
    lastFont = rtb.Font;
    //..

}

Font lastSelectionFont;
Font lastFont;
private void richTextBox1_TextChanged(object sender, EventArgs e)
{

    if (rtb.SelectionLength > 0)
    {
        lastSelectionFont = rtb.SelectionFont;
        rtb.SelectionFont = new Font(rtb.SelectionFont.FontFamily, 
                                Convert.ToInt16(combo_sizes.Text));
    }
    else
    {
        lastFont = rtb.Font;
        rtb.Font = new Font(rtb.Font.FontFamily, 
                               Convert.ToInt16(combo_sizes.Text));
    }
}

请注意,除非将SelectionFont设置为null,否则它不会为空。当没有选择时,您可能遇到了问题。
但是,我不确定您对“保存”以前的Forn的想法。想想WordPad:它也不做任何这样的事情。将您使用的所有字体添加到字体列表中,甚至包括它们的颜色和漂亮的字体名称和样式,听起来非常有吸引力。

你好,感谢您的帮助。我在创建lastSelectionFont和lastFont时遇到了问题,出现了以下错误: “字段初始值设定项不能引用非静态字段、方法或属性”。 - Carlos Chévez
是的,我的错 - 只有在编译时可计算的表达式才能像我这样被赋值。抱歉,我已经更改了代码并将初始化移动到窗体的构造函数中。 - TaW
为什么要创建一个新的ComboBox? - Carlos Chévez
哎呀!我又犯了一个小错误。我使用了这两行代码来避免在我的测试程序中重命名控件... 我已经将它们删除了,再次抱歉;-) - TaW

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接