更改任一元素时如何保持 RichText 格式(粗体/斜体/等)?

发布于 2024-10-22 14:12:19 字数 3249 浏览 1 评论 0原文

我有一个富文本框,其中可能包含一个包含粗体、斜体甚至不同字体和大小元素的字符串。如果我选择整个字符串,包括所有差异,如何“加粗”该字符串而不将整个字符串转换为仅具有“粗体”属性的通用字体?

例如:我想将“This is some text”转换为“This is some text

请注意,“is some”仍然是斜体,“text”仍然是不同的字体。

我目前所拥有的非常简单:

private void tsBold_Click(object sender, EventArgs e)
{
    if (rtb.SelectionFont == null) return;

    Font f;

    if (tsBold.Checked)
        f = new Font(rtb.SelectionFont, FontStyle.Bold);
    else
        f = new Font(rtb.SelectionFont, FontStyle.Regular);

    rtb.SelectionFont = f;

    rtb.Focus();
}

当然,这会将完全相同的字体应用于整个选择。有什么方法可以将“粗体”附加到现有字体吗?

回答 虽然下面的“官方”答案只是冰山一角,但它是我需要朝正确方向前进的推动力。谢谢你的提示。

这是我的官方修复:

我将其添加到我的 RichTextBox 对象中:

    /// <summary>
    ///     Change the richtextbox style for the current selection
    /// </summary>
    public void ChangeFontStyle(FontStyle style, bool add)
    {
        //This method should handle cases that occur when multiple fonts/styles are selected
        // Parameters:-
        //  style - eg FontStyle.Bold
        //  add - IF true then add else remove

        // throw error if style isn't: bold, italic, strikeout or underline
        if (style != FontStyle.Bold
            && style != FontStyle.Italic
            && style != FontStyle.Strikeout
            && style != FontStyle.Underline)
            throw new System.InvalidProgramException("Invalid style parameter to ChangeFontStyle");

        int rtb1start = this.SelectionStart;
        int len = this.SelectionLength;
        int rtbTempStart = 0;

        //if len <= 1 and there is a selection font then just handle and return
        if (len <= 1 && this.SelectionFont != null)
        {
            //add or remove style 
            if (add)
                this.SelectionFont = new Font(this.SelectionFont, this.SelectionFont.Style | style);
            else
                this.SelectionFont = new Font(this.SelectionFont, this.SelectionFont.Style & ~style);

            return;
        }

        using (EnhancedRichTextBox rtbTemp = new EnhancedRichTextBox())
        {
            // Step through the selected text one char at a time    
            rtbTemp.Rtf = this.SelectedRtf;
            for (int i = 0; i < len; ++i)
            {
                rtbTemp.Select(rtbTempStart + i, 1);

                //add or remove style 
                if (add)
                    rtbTemp.SelectionFont = new Font(rtbTemp.SelectionFont, rtbTemp.SelectionFont.Style | style);
                else
                    rtbTemp.SelectionFont = new Font(rtbTemp.SelectionFont, rtbTemp.SelectionFont.Style & ~style);
            }

            // Replace & reselect
            rtbTemp.Select(rtbTempStart, len);
            this.SelectedRtf = rtbTemp.SelectedRtf;
            this.Select(rtb1start, len);
        }
        return;
    }

然后我更改了单击方法以使用以下模式:

    private void tsBold_Click(object sender, EventArgs e)
    {
        enhancedRichTextBox1.ChangeFontStyle(FontStyle.Bold, tsBold.Checked);

        enhancedRichTextBox1.Focus();
    }

I have a rich text box that may contain a string that has elements of bold, italics, or even different fonts and sizes. If I select the entire string, including all of the differences, how can I "Bold" that string without converting the entire string to the generic font with just a "bold" attribute?

For example: I want to turn "This is some text" into "This is some text"

Note that "is some" remained italicized and "text" remained a different font.

What I currently have is quite simplistic:

private void tsBold_Click(object sender, EventArgs e)
{
    if (rtb.SelectionFont == null) return;

    Font f;

    if (tsBold.Checked)
        f = new Font(rtb.SelectionFont, FontStyle.Bold);
    else
        f = new Font(rtb.SelectionFont, FontStyle.Regular);

    rtb.SelectionFont = f;

    rtb.Focus();
}

Of course, this is going to apply the exact same font to the entire selection. Is there any way to just append "bold" to the existing font(s)?

ANSWER
While the "official" answer below is just the tip of the iceberg, it was the push I needed in the right direction. Thank you for the tip.

Here's my official fix:

I added this to my RichTextBox object:

    /// <summary>
    ///     Change the richtextbox style for the current selection
    /// </summary>
    public void ChangeFontStyle(FontStyle style, bool add)
    {
        //This method should handle cases that occur when multiple fonts/styles are selected
        // Parameters:-
        //  style - eg FontStyle.Bold
        //  add - IF true then add else remove

        // throw error if style isn't: bold, italic, strikeout or underline
        if (style != FontStyle.Bold
            && style != FontStyle.Italic
            && style != FontStyle.Strikeout
            && style != FontStyle.Underline)
            throw new System.InvalidProgramException("Invalid style parameter to ChangeFontStyle");

        int rtb1start = this.SelectionStart;
        int len = this.SelectionLength;
        int rtbTempStart = 0;

        //if len <= 1 and there is a selection font then just handle and return
        if (len <= 1 && this.SelectionFont != null)
        {
            //add or remove style 
            if (add)
                this.SelectionFont = new Font(this.SelectionFont, this.SelectionFont.Style | style);
            else
                this.SelectionFont = new Font(this.SelectionFont, this.SelectionFont.Style & ~style);

            return;
        }

        using (EnhancedRichTextBox rtbTemp = new EnhancedRichTextBox())
        {
            // Step through the selected text one char at a time    
            rtbTemp.Rtf = this.SelectedRtf;
            for (int i = 0; i < len; ++i)
            {
                rtbTemp.Select(rtbTempStart + i, 1);

                //add or remove style 
                if (add)
                    rtbTemp.SelectionFont = new Font(rtbTemp.SelectionFont, rtbTemp.SelectionFont.Style | style);
                else
                    rtbTemp.SelectionFont = new Font(rtbTemp.SelectionFont, rtbTemp.SelectionFont.Style & ~style);
            }

            // Replace & reselect
            rtbTemp.Select(rtbTempStart, len);
            this.SelectedRtf = rtbTemp.SelectedRtf;
            this.Select(rtb1start, len);
        }
        return;
    }

I then changed the click methods to use the following pattern:

    private void tsBold_Click(object sender, EventArgs e)
    {
        enhancedRichTextBox1.ChangeFontStyle(FontStyle.Bold, tsBold.Checked);

        enhancedRichTextBox1.Focus();
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

甜柠檬 2024-10-29 14:12:19

RTB 对此的支持不太。您甚至无法发现所选内容中具有相同字体样式的字符范围。首先检查 SelectionFont 属性,如果选择包含混合样式,则该属性将为 null。如果是这种情况,您必须通过设置 SelectionStart 和 SelectionLength 属性一次迭代一个字符,读取 SelectionFont 直到它发生变化。将更改后的字体应用到您发现的范围。

检查这个答案寻找方法以保持相当快且无闪烁。

请注意,使用 RTB 实现编辑器是 codeproject.com 上最受欢迎的主题。借用代码(即使不是整个项目)也是减轻痛苦的好方法。

RTB does not support this well. You cannot even discover the range of characters within the selection that has the same font style. Start by checking the SelectionFont property first, it will be null if the selection contains a mix of styles. If that's the case, you'll have to iterate the selection one character at a time by setting the SelectionStart and SelectionLength properties, read the SelectionFont until it changes. Apply the changed font to the range you discovered.

Check this answer for a way to keep this reasonably quick and flicker-free.

Note that implementing an editor with RTB is a favorite topic at codeproject.com. Borrowing code, if not the entire project, is a good way to lessen the pain.

抚笙 2024-10-29 14:12:19

要使文本选择变为粗体,同时保持其格式完整,请使用以下命令:

if (rtb.SelectionFont !=null)
    rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style | FontStyle.Bold);

要在保持其格式完整的同时取消粗体文本选择,请使用此命令:

if (rtb.SelectionFont !=null)
    rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style & ~FontStyle.Bold);

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

现在要对 RichTextBox 中的所有文本执行此操作,

现在要将 RichTextBox 的整个文本加粗/取消加粗,同时保持其他格式不变,您需要循环遍历 RichTextBox 的所有字符并一一应用加粗/取消加粗。这是完整的代码:

private void tsBold_Click(object sender, EventArgs e)
{
    //Loop through all the characters of richtextbox
    for (int i = 0; i < rtb.TextLength; i++)
    {
        //Select current character
        rtb.Select(i, 1);

        if (tsBold.Checked)
            //Make the selected character Bold
            rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style | FontStyle.Bold);
        else
            //Make the selected character unBold
            rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style & ~FontStyle.Bold);
    }
}

如果您需要切换粗体的现有状态(即使非粗体文本变为粗体并使粗体文本变为非粗体),请改用以下代码:

        if (rtb.SelectionFont.Style.ToString().Contains("Bold")) //If the selected character is Bold
            //Make the selected character unBold
            rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style & ~FontStyle.Bold);
        else //If the selected character is unBold
            //Make the selected character Bold
            rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style | FontStyle.Bold);

To make a text selection bold while keeping its formatting intact, use this:

if (rtb.SelectionFont !=null)
    rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style | FontStyle.Bold);

To unBold text selection while keeping its formatting intact, use this:

if (rtb.SelectionFont !=null)
    rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style & ~FontStyle.Bold);

Note that above code will only work, if all the selected text has same formatting (font size, style etc). This is detected by checking the SelectionFont property first, it will be null if the selection contains a mix of styles.

Now to do this with all text in richtextbox,

Now to Bold/unBold the entire text of richtextbox while keeping other formatting intact, you need to loop through all the characters of the richtextbox and apply Bold/unBold one by one. Here is the complete code:

private void tsBold_Click(object sender, EventArgs e)
{
    //Loop through all the characters of richtextbox
    for (int i = 0; i < rtb.TextLength; i++)
    {
        //Select current character
        rtb.Select(i, 1);

        if (tsBold.Checked)
            //Make the selected character Bold
            rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style | FontStyle.Bold);
        else
            //Make the selected character unBold
            rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style & ~FontStyle.Bold);
    }
}

If you need to toggle the existing state of Bold (i.e. make non-bold text Bold and make bold text unBold), use this instead:

        if (rtb.SelectionFont.Style.ToString().Contains("Bold")) //If the selected character is Bold
            //Make the selected character unBold
            rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style & ~FontStyle.Bold);
        else //If the selected character is unBold
            //Make the selected character Bold
            rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style | FontStyle.Bold);
懒的傷心 2024-10-29 14:12:19

如果您还想更改其字体系列和字体大小,您可以使用此方法:
汉斯是对的,你必须迭代每个字符。

  private void ChangeFontStyleForSelectedText(string familyName, float? emSize, FontStyle? fontStyle, bool? enableFontStyle)
    {
        _maskChanges = true;
        try
        {
            int txtStartPosition = txtFunctionality.SelectionStart;
            int selectionLength = txtFunctionality.SelectionLength;
            if (selectionLength > 0)
                using (RichTextBox txtTemp = new RichTextBox())
                {
                    txtTemp.Rtf = txtFunctionality.SelectedRtf;
                    for (int i = 0; i < selectionLength; ++i)
                    {
                        txtTemp.Select(i, 1);
                        txtTemp.SelectionFont = RenderFont(txtTemp.SelectionFont, familyName, emSize, fontStyle, enableFontStyle);
                    }

                    txtTemp.Select(0, selectionLength);
                    txtFunctionality.SelectedRtf = txtTemp.SelectedRtf;
                    txtFunctionality.Select(txtStartPosition, selectionLength);
                }
        }
        finally
        {
            _maskChanges = false;
        }
    }

      /// <summary>
    /// Changes a font from originalFont appending other properties
    /// </summary>
    /// <param name="originalFont">Original font of text</param>
    /// <param name="familyName">Target family name</param>
    /// <param name="emSize">Target text Size</param>
    /// <param name="fontStyle">Target font style</param>
    /// <param name="enableFontStyle">true when enable false when disable</param>
    /// <returns>A new font with all provided properties added/removed to original font</returns>
    private Font RenderFont(Font originalFont, string familyName, float? emSize, FontStyle? fontStyle, bool? enableFontStyle)
    {
        if (fontStyle.HasValue && fontStyle != FontStyle.Regular && fontStyle != FontStyle.Bold && fontStyle != FontStyle.Italic && fontStyle != FontStyle.Underline)
            throw new System.InvalidProgramException("Invalid style parameter to ChangeFontStyleForSelectedText");

        Font newFont;
        FontStyle? newStyle = null;
        if (fontStyle.HasValue)
        {
            if (fontStyle.HasValue && fontStyle == FontStyle.Regular)
                newStyle = fontStyle.Value;
            else if (originalFont != null && enableFontStyle.HasValue && enableFontStyle.Value)
                newStyle = originalFont.Style | fontStyle.Value;
            else
                newStyle = originalFont.Style & ~fontStyle.Value;
        }

        newFont = new Font(!string.IsNullOrEmpty(familyName) ? familyName : originalFont.FontFamily.Name,
                            emSize.HasValue ? emSize.Value : originalFont.Size,
                            newStyle.HasValue ? newStyle.Value : originalFont.Style);
        return newFont;
    }

有关更多说明,您可以访问: http://how-to-code-net.blogspot.ro/2014/01/how-to-make-custom-richtextbox-control.html

In case you want also to change its font family and font size you could use this method:
Hans is right, you have to iterate each character.

  private void ChangeFontStyleForSelectedText(string familyName, float? emSize, FontStyle? fontStyle, bool? enableFontStyle)
    {
        _maskChanges = true;
        try
        {
            int txtStartPosition = txtFunctionality.SelectionStart;
            int selectionLength = txtFunctionality.SelectionLength;
            if (selectionLength > 0)
                using (RichTextBox txtTemp = new RichTextBox())
                {
                    txtTemp.Rtf = txtFunctionality.SelectedRtf;
                    for (int i = 0; i < selectionLength; ++i)
                    {
                        txtTemp.Select(i, 1);
                        txtTemp.SelectionFont = RenderFont(txtTemp.SelectionFont, familyName, emSize, fontStyle, enableFontStyle);
                    }

                    txtTemp.Select(0, selectionLength);
                    txtFunctionality.SelectedRtf = txtTemp.SelectedRtf;
                    txtFunctionality.Select(txtStartPosition, selectionLength);
                }
        }
        finally
        {
            _maskChanges = false;
        }
    }

      /// <summary>
    /// Changes a font from originalFont appending other properties
    /// </summary>
    /// <param name="originalFont">Original font of text</param>
    /// <param name="familyName">Target family name</param>
    /// <param name="emSize">Target text Size</param>
    /// <param name="fontStyle">Target font style</param>
    /// <param name="enableFontStyle">true when enable false when disable</param>
    /// <returns>A new font with all provided properties added/removed to original font</returns>
    private Font RenderFont(Font originalFont, string familyName, float? emSize, FontStyle? fontStyle, bool? enableFontStyle)
    {
        if (fontStyle.HasValue && fontStyle != FontStyle.Regular && fontStyle != FontStyle.Bold && fontStyle != FontStyle.Italic && fontStyle != FontStyle.Underline)
            throw new System.InvalidProgramException("Invalid style parameter to ChangeFontStyleForSelectedText");

        Font newFont;
        FontStyle? newStyle = null;
        if (fontStyle.HasValue)
        {
            if (fontStyle.HasValue && fontStyle == FontStyle.Regular)
                newStyle = fontStyle.Value;
            else if (originalFont != null && enableFontStyle.HasValue && enableFontStyle.Value)
                newStyle = originalFont.Style | fontStyle.Value;
            else
                newStyle = originalFont.Style & ~fontStyle.Value;
        }

        newFont = new Font(!string.IsNullOrEmpty(familyName) ? familyName : originalFont.FontFamily.Name,
                            emSize.HasValue ? emSize.Value : originalFont.Size,
                            newStyle.HasValue ? newStyle.Value : originalFont.Style);
        return newFont;
    }

For more explanations you could go to: http://how-to-code-net.blogspot.ro/2014/01/how-to-make-custom-richtextbox-control.html

维持三分热 2024-10-29 14:12:19

我还没有根据消耗更多内存的字体对象引用来测试它,但这

应该可以工作

        if(rtbCaseContent.SelectedText.Length > 0 ) 
        {
            // calculate font style 
            FontStyle style = FontStyle.Underline;
            Font selectedFont = rtbCaseContent.SelectionFont;

            if (rtbCaseContent.SelectionFont.Bold == true)
            {
                style |= FontStyle.Bold;
            }
            if (rtbCaseContent.SelectionFont.Italic == true)
            {
                style |= FontStyle.Italic;
            }

            rtbCaseContent.SelectionFont = new Font(selectedFont,style);
        }           

I am yet to test it in terms of Font object references consuming more memory however

This should work

        if(rtbCaseContent.SelectedText.Length > 0 ) 
        {
            // calculate font style 
            FontStyle style = FontStyle.Underline;
            Font selectedFont = rtbCaseContent.SelectionFont;

            if (rtbCaseContent.SelectionFont.Bold == true)
            {
                style |= FontStyle.Bold;
            }
            if (rtbCaseContent.SelectionFont.Italic == true)
            {
                style |= FontStyle.Italic;
            }

            rtbCaseContent.SelectionFont = new Font(selectedFont,style);
        }           
为你鎻心 2024-10-29 14:12:19

如果您想在同一文本上应用更多 FontStyle,您可以使用按位运算符 |和〜
|添加新样式并删除现有样式
例如

Font aFont=new Font(aPrototypeFont, anotherFont.Style | FontStyle.Bold); 

if you want to apply more FontStyle's on the same text you can use bitwise operators | and ~
| adds a new style and ~ removes an existing style
for example

Font aFont=new Font(aPrototypeFont, anotherFont.Style | FontStyle.Bold); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文