Tech Off Thread

23 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

RichTextBox .NET FontStyle.Bold problem

Back to Forum: Tech Off
  • User profile image
    mw5300

    So I have this RichTextBox in a winforms app written in C#. I am trying to make some toolbar buttons change some selected text to bold, italic, or underline. Right now I am using some code that looks like this:
    if (this.MainRichBox.SelectionFont != null)
                    {
                        System.Drawing.Font currentFont = this.MainRichBox.SelectionFont;
                        System.Drawing.FontStyle newFontStyle;

                        if (this.MainRichBox.SelectionFont.Bold == true)
                        {
                            newFontStyle = FontStyle.Regular;
                            this.Bold.Checked = false;
                        }
                        else
                        {
                            newFontStyle = FontStyle.Bold;
                            this.Bold.Checked = true;
                        }

                        this.MainRichBox.SelectionFont = new Font(
                           currentFont.FontFamily,
                           currentFont.Size,
                           newFontStyle
                        );
                    }

    That I call whenever I press the bold button(for example). My problem is that if I try to make some Italic text Bold, then it stops being Italic and becaomes bold. I want it to be both Bold and Italic when I click Bold on some selected Italic text.

    Thanks,
    Mark

  • User profile image
    SimonJ

    You could try the following instead...

    Dim ExistingFont As Font = RichTextBox1.SelectionFont
    Dim NewFontStyle As New FontStyle
    With ExistingFont
       NewFontStyle = -((Not .Bold) * FontStyle.Bold)
       NewFontStyle += -(.Italic * FontStyle.Italic)
       NewFontStyle += -(.Underline * FontStyle.Underline)
       NewFontStyle += -(.Strikeout * FontStyle.Strikeout)
       RichTextBox1.SelectionFont = New Font(ExistingFont, NewFontStyle)
    End With




    This copies all the FontStyle settings into the new font but toggles the bold
    Move the (Not xxx) from Bold to Italic for the Italic toggle button. Beware that
    this does not cope well if your selection spans text with more than one font or style.
    All the selected text will change to be one font and style.

    SimonJ





  • User profile image
    mw5300

    Thanks, SimonJ.

    Is there any way I can preserve all the formating of the text even if the selection spans some Italic text, and some Underlined text when I add bold? I'm looking for the MS Word style of changing Bold, Italic and Underline.

    P.S. I don't know VB, I only know C#.

    Thanks for your help,
    Mark

  • User profile image
    Angus

    The code for C# would be:

    Font ExistingFont = richTextBox1.SelectionFont;

    FontStyle NewFontStyle = new FontStyle();

    NewFontStyle = -((Not.Bold) * FontStyle.Bold);

    NewFontStyle +=- ((Not.Italic) * FontStyle.Italic);

    NewFontStyle +=- ((Not.Underline) * FontStyle.Underline);

    NewFontStyle +=- ((Not.Strikeout) * FontStyle.Strikeout);

    richTextBox1.Font = new Font(ExistingFont, NewFontStyle);

    I believe this will work, although you must follow the rules about changing the (Not.). If this doesn't work please tell me and I will try and sort it out.

    Angus Higgins

  • User profile image
    SimonJ

    The code I gave would be the click event handler for the Bold button. It has only one "NOT" in it to toggle bold text. The Italic button click event handler would also have only one "NOT" in it but on a different line to toggle italic text.

    I can't remember what the C# equivalent of With ... End With is but that bit is significant.

    SimonJ

  • User profile image
    SimonJ

    If you select text which includes a mix of italic and non-italic text and click the italic button, you would like all the italic text to go non-italic and all the non-italic text to go italic. You'd also like it to leave any bold or non-bold attributes exactly as they are in the selected text.

    This is difficult. The RichTextBox reports the font and style for the first character (I think) in the selection so you are actually generating a new font/style based on the font/style of the first character and then applying that new font/style to the whole selection. If you want to do anything different I think you'd either have to iterate through the selected text a character at a time or you'd have to parse the RTF for that selection, mangle that and replace the selected RTF with your changed version.

    SimonJ

  • User profile image
    Sven Groot

    SimonJ wrote:
    You could try the following instead...

    Dim ExistingFont As Font = RichTextBox1.SelectionFont
    Dim NewFontStyle As New FontStyle
    With ExistingFont
       NewFontStyle = -((Not .Bold) * FontStyle.Bold)
       NewFontStyle += -(.Italic * FontStyle.Italic)
       NewFontStyle += -(.Underline * FontStyle.Underline)
       NewFontStyle += -(.Strikeout * FontStyle.Strikeout)
       RichTextBox1.SelectionFont = New Font(ExistingFont, NewFontStyle)
    End With




    This copies all the FontStyle settings into the new font but toggles the bold
    Move the (Not xxx) from Bold to Italic for the Italic toggle button. Beware that
    this does not cope well if your selection spans text with more than one font or style.
    All the selected text will change to be one font and style.

    SimonJ






    Don't use arithmic operators for logic operations.

    Try this instead:

    richTextBox1.SelectionFont = new Font(richTextBox1.SelectionFont, richTextBox1.SelectionFont.Style ^ FontStyle.Bold);

    The xor operator will turn the bit for the specified style on if it's not present and off it is present, thus toggling the selected option while leaving the rest alone.

    EDIT: It doesn't solve the multiple styles in one selection problem, though.

  • User profile image
    ScanIAm

    Sven Groot wrote:


    Don't use arithmic operators for logic operations.


    Thank heavens someone said this.  I was about to post this to http://www.thedailywtf.com/

  • User profile image
    SimonJ

    Well that's even better.
    I'd forgotten about the XOR operator.

    I wonder if it is fast enough to use while iterating through every character in the selection. I wonder if the RTF control is sensible and could aggregate regions of text with the same attributes if you altered the font/style for every individual character. I suspect the RTF it generates would get bloated with millions of font/style changes pretty quickly.

    SimonJ

  • User profile image
    Sven Groot

    SimonJ wrote:
    Well that's even better.
    I'd forgotten about the XOR operator.

    Even so, you still should've used regular and/or. You never, ever use arithmic operators for bitwise logic. Never.

  • User profile image
    SimonJ

    So go on, enlighten me/us.

    Why not?

    I suspect it could be because some value you're dealing with might not be a pure power of two and using + rather than OR might have unintended consequences, etc.

    But, when you're dealing with Enum Flags each enum must be a pure power of two (a single bit set) and 4+8 is far more understandable than 4 OR 8.

    [devil's advocate mode OFF] Smiley

    SimonJ

  • User profile image
    Sven Groot

    Off the top of my head, four reasons:

    1. More semantic. You are not adding values, you're combining bit flags. You're doing bitwise logic, so use bitwise logic. You could implement arithmetic operations with bitwise operators, but you don't, you use arithmetic operators. Likewise you use bitwise operators for bitwise operations.

    2. Safer. Combining values with + doesn't always have the intended result. In your case, you're building the value up from the ground, so you know the start value is zero, so you are relatively safe. But if you're manipulating an existing value, using + could mean trouble. Lets say I do this: originalFontStyle + FontStyle.Bold. That's fine if originalFontStyle doesn't contain Bold already. If it does however already have bold, then the bold bit will actually be set to zero and the next bit will be set (unless that already is set, in which case the next, etc. etc., you could end up unsetting a lot of unintended bits). If instead I do originalFontStyle | FontStyle.Bold, the result is clear: originalFontStyle with the bold bit set, and all other bits unmodified. Multiplication is even worse. In the worst case, you could even overflow the value and cause an exception. Even in your situation, maybe some other programmer some time in the future needs to maintain the code, and makes some modification so that the Bold bit accidentally gets set twice. No problem if you used |, huge problem if you used +.

    3. More easily understandable. Without the problem statement, your code would require quite a bit of thinking on my part to see what you're intending to do. Even with the context of this thread, there was a moment of "wait, what's he trying to do?", simply because I don't expect people to use arithmic operators like this.

    4. It's faster. It may not matter for a great many applications, but sometimes it does. Say for instance you're attempting to convert 16 bit colour values to 24 bit colour values, in a tight loop where you're decoding a video (so several tens of thousands of pixels, 24 times per second, that need the operation done). Do it with +, -, * and /, and it'll be too slow to playback the video.

  • User profile image
    mw5300

    "EDIT: It doesn't solve the multiple styles in one selection problem, though."

    Is there a way to solve this problem? Basically I wan't it to respect if parts the selection are already bold, italic or underline and just toggle the bold italic or underline.

    Thanks!
    Mark

  • User profile image
    SimonJ

    Good explanations.

    One question springs to mind is why are arithmetic operators even allowed on enum or enum flags? They may be integers underneath but it sounds like you shouldn't be allowed to use mathematical operators with them.

    SimonJ

  • User profile image
    Sven Groot

    This seems to do the trick:


    private void SetFontStyle(RichTextBox rtb, FontStyle style)
    {
    int selectionStart = rtb.SelectionStart;
    int selectionLength = rtb.SelectionLength;
    int selectionEnd = selectionStart + selectionLength;
    for( int x = selectionStart; x < selectionEnd; ++x )
    {
    // Set temporary selection
    rtb.Select(x, 1);
    // Toggle font style of the selection
    rtb.SelectionFont = new Font(rtb.SelectionFont, rtb.SelectionFont.Style ^ style);
    }
    // Restore the original selection
    rtb.Select(selectionStart, selectionLength);
    }


    Call with for instance:
    SetFontStyle(someRichtTextBox, FontStyle.Bold)

  • User profile image
    Sven Groot

    SimonJ wrote:
    Good explanations.

    One question springs to mind is why are arithmetic operators even allowed on enum or enum flags? They may be integers underneath but it sounds like you shouldn't be allowed to use mathematical operators with them.

    To quote Gandalf: "even the wisest cannot see all ends".

    There may yet be some situation where, for whatever reason, applying arithmetic operators to an enum is what you must do. That I can't think of a situation in which that's warranted, doesn't mean there isn't one. All I know for certain is that this wasn't one of those situations. Smiley

    Or, to quote the C++ FAQ Lite: "[...] sometimes you will have to choose between a bunch of bad options. When that happens, the best you can hope for is to choose the least bad of the alternatives, the lesser of the "evils." "

  • User profile image
    footballism

    Sven Groot wrote:

     to quote the C++ FAQ Lite: "[...] sometimes you will have to choose between a bunch of bad options. When that happens, the best you can hope for is to choose the least bad of the alternatives, the lesser of the "evils." "


    You have already enlightened me on this Sven:P

    Sheva

  • User profile image
    mw5300

    Thanks Sven! It works great.

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.