Carlos Chévez
Carlos Chévez

Reputation: 31

How to change the font of multiple sizes in richtextbox in C#?

I have a richtextbox and I would like to make it work like WordPad. My problem is that, for example, if I type "123" using the Calibri font, and then "456" using the Arial font and I want to change the size of 2345 it won't let me to do it because they have two different font types. This is where I have the problem:

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));
}

I know tha when the selected text in the rtb contains multiple fonts the SelectionFont equals to null, so in that case I have made it to get the selected text's size and font from two comboboxes, but I would like to change the size without losing its original font. Is there a solution?

Thanks

Upvotes: 3

Views: 2737

Answers (3)

D.Kastier
D.Kastier

Reputation: 3015

I needed the same here. And I didn't find the best solution... So, here is the Ugly one.

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;
    }
}

IMPROVED VERSION

This is a better version, its includes:

  1. Disabling the RichTextBox drawing (when changing the font);
  2. Prevents the "char-by-char modification" to go to the Undo/Redo stack;
  3. Show the WaitCursor when performing the change.

Requirements

  1. External.cs
  2. RichOLE.cs
  3. (Optional) RicherTextBox -- I built my Code around this one, it is a nice start to build a WordPad-like project

The code

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;
    }
}

Upvotes: 0

TaW
TaW

Reputation: 54433

There are two built-in fonts in a RichTextBox (RTB):

  • Font is the one that will be used after for any input. So if you want to switch to another font, this is what you should set
  • SelectionFont however is the font of the current selection. This will change with the selection but it is also used to set font of part of the text that has already been entered.

But there can be only one of either at a time and place. If you want to switch back to a standard Front you need to keep a standard Font somewhere.

Or you can store all fonts you use in a List and you can offer them in a comboBox.

Please also note that:

  • All formatting after the text has been entered must be done be selecting a part and then changing the properties of that selection: Font, Colors, Styles..
  • After any part of the Text has been formatted in any way you must not change the text directly in your code but only use AppendText, Copy, Cut, Past or else you'll you'll mess up the formatting!

Your code may work like this:

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));
    }
}

Note that the SelectionFont won't be null ubnless you set it to null. You probably have hit problems when there was no selection..

But again, I'm not sure about your ideas of 'saving' the previous Forn. Think of wordPad: It doesn't do anythink like that either. Adding all fonts you use into a List of Fonts, maybe even with theris colors, and nice names as font&styles sound very attractive.

Upvotes: 0

Shaharyar
Shaharyar

Reputation: 12439

Break your selected text into chars. Get each char's Font, and change its size.

Upvotes: 1

Related Questions