11

Can somebody please explain how I would go about measuring the string inside a richtextbox control so that the I can automatically resize the richtextbox control according to its content?

Thank you

Edit:

I've thought about it, and since the below answer won't work if there are different fonts in the RichTextBox Control, what if, I could get the upper-left coords of the richtextbox control and then get the bottom-right coords of the very last line of text inside the rtb. That would essentially give me the Width and Height of the string inside the RichTextBox Control. Is this possible? Or is this a bad idea to do it this way?

6 Answers6

7

Put the following code in the ContentsResized event:

Private Sub rtb_ContentsResized(ByVal sender As Object, ByVal e As System.Windows.Forms.ContentsResizedEventArgs) Handles txtQuestion.ContentsResized
        Dim h = e.NewRectangle.Height, w = e.NewRectangle.Width
        h = Math.Max(h, sender.Font.Height)
        h = Math.Min(h, Me.ClientSize.Height - 10 - sender.Top)
        h += sender.Height - sender.ClientSize.Height + 1
        sender.Height = h
End Sub
Oliver
  • 43,366
  • 8
  • 94
  • 151
Prepmania.com
  • 71
  • 1
  • 2
  • `ContentsResized` and `e.NewRectangle` did the trick for me. The other usual suspects e.g. `AutoSize`, `GetPreferredSize` don't seem to work properly for `RichTextBox`. – Ben Challenor Mar 02 '12 at 14:36
  • This doesn't work. The height ends up too short, and even if I modify this to set sender.Width = w, the width doesn't change at all. – Nick Oct 19 '18 at 18:51
3

Assuming that someone is typing into the control, you could use an event to fire every time a character is entered (increment counter) and decrement when it is deleted. This would give you a true count.

Edit:

Have you tried this to adjust the height?

richTextBox1.Height = (int)(1.5 * richTextBox1.Font.Height) + richTextBox1.GetLineFromCharIndex(richTextBox1.Text.Length + 1) * richTextBox1.Font.Height + 1 + richTextBox1.Margin.Vertical;

richTextBox1.SelectionStart = 0;

richTextBox1.SelectionStart = richTextBox1.Text.Length;

Or you can do this using Width:

Graphics g = Graphics.FromHwnd(richTextBox1.Handle);

SizeF f = g.MeasureString(richTextBox1.Text, richTextBox1.Font);
richTextBox1.Width = (int)(f.Width)+5;
  • This is currently what I am doing, although you can't account for font styles/sizes this way, and eventually the rtb won't be able to keep up and the text would overflow –  Mar 02 '10 at 17:21
  • No offense, but this produces very ugly results. There has to be a way to do this without looking like the RichTextBox is about to explode through my monitor. –  Mar 03 '10 at 17:20
  • Hmm, it seemed to work fine here but I am not applying any font styles –  Mar 03 '10 at 17:59
  • This might work for simple TextBoxes, but it does not work for RichTextBoxes that can have bold words, multiple fonts used, and multiple font sizes. – Nick Oct 19 '18 at 18:54
3

Try calling GetPreferredSize(Size.Empty). It is defined in the Control class, and if overriden property by the RichTextBoxControl, ought to give you what you are looking for.

If you pass something other than Size.Empty into the method, then it will use that value as a maximum constraint. Using Size.Empty means that the potential size is unbounded.

Nick
  • 5,875
  • 1
  • 27
  • 38
  • you can even call it with the width `GetPreferredSize(new Size(width, 0))` and you can get the height from the return Size of that call – Rémi Apr 16 '13 at 19:09
  • This does not work. The height and width returned by GetPerferredSize are both too short. – Nick Oct 19 '18 at 18:52
0

You can measure a string by calling TextRenderer.MeasureText.

However, if the text contains multiple fonts, this will not work.

EDIT: You're looking for the GetPositionFromCharIndex method.
Note that if there are multiple lines, you should take the max of the X coordinates of the last character on each line.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Thanks. I don't quite understand that page. Why does it draw text? Can it just send me back a width and height value, so I can reset the Size of the RichTextBox to the new size? –  Mar 02 '10 at 17:09
  • `TextRenderer.MeasureText` doesn't draw anything; it simply returns the size of the text in pixels. – SLaks Mar 02 '10 at 17:19
0

Add on to bathineni's great answer:

Background: I needed to measure RTF output height for rendering onto paper and because I have custom dynamic page headers/footers I needed to control paging).

(RichTextBox.GetLineFromCharIndex let me down because of complex RTF; including lines & multi column Tables with wordwrap).

Anyhow all was working fine, until someone else used my app with the dreaded windows "Make text and other items larger or smaller" (DPI settings.) - in short now measuring bigger sized fonts it screwed up the page length calculations. (the printer still rendered the text and columns correctly - only the page lengths were now all wrong.)

Only factoring DPI difference failed as in short bigger text didn't fit properly into source RTF tx and cellx values.

Anyhow, in case others are doing similar crazy things bit of trial and error came up with the following (eventually very few) mods to the bathineni CalculateRichTextHeight method:

RichTextBox richTextBox = new RichTextBox();     // same as original
int dpix = richTextBox.CreateGraphics().DpiX;    // get dpi
richTextBox.WordWrap = true;                     // I needed this, you many not
  // ... set size etc - same as original answer
richTextBox.Scale(new System.Drawing.SizeF(dpix / 96, dpix / 96));  // scale RTB
  // ...
  // 96? my original calculations based on windows default 96dpi settings.

Seems the otherwise obscure Control.Scale(sizef) is actually useful for something after all.

Note: if converting results to actual printed lines, (in my case all my \pard's were "\sl-240\slmult0" which comes out to 16 (pix?) per line) also remember to re-factor the divisor. i.e. in my case:

lines = height / (int)(16 * (dpix / 96))
Rob
  • 444
  • 3
  • 10
0

I found a solution for the Rich text box height issues.. i have modified it a for general use..

Create following structs in your application....

[StructLayout(LayoutKind.Sequential)]
    public struct RECT {
        public Int32 left;
        public Int32 top;
        public Int32 right;
        public Int32 bottom;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SCROLLBARINFO {
        public Int32 cbSize;
        public RECT rcScrollBar;
        public Int32 dxyLineButton;
        public Int32 xyThumbTop;
        public Int32 xyThumbBottom;
        public Int32 reserved;
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
        public Int32[] rgstate;
    }

Create following private variables in your class for form (where ever you need to calculate rich text height)

private UInt32 SB_VERT = 1;
        private UInt32 OBJID_VSCROLL = 0xFFFFFFFB;

        [DllImport("user32.dll")]
        private static extern
            Int32 GetScrollRange(IntPtr hWnd, UInt32 nBar, out Int32 lpMinPos, out Int32 lpMaxPos);

        [DllImport("user32.dll")]
        private static extern
            Int32 GetScrollBarInfo(IntPtr hWnd, UInt32 idObject, ref SCROLLBARINFO psbi);

Add following method to your Class for form

private int CalculateRichTextHeight(string richText) {
            int height = 0;
            RichTextBox richTextBox = new RichTextBox();
            richTextBox.Rtf = richText;
            richTextBox.Height = this.Bounds.Height;
            richTextBox.Width = this.Bounds.Width;
            richTextBox.WordWrap = false;
            int nHeight = 0;
            int nMin = 0, nMax = 0;

            SCROLLBARINFO psbi = new SCROLLBARINFO();
            psbi.cbSize = Marshal.SizeOf(psbi);

            richTextBox.Height = 10;
            richTextBox.ScrollBars = RichTextBoxScrollBars.Vertical;

            int nResult = GetScrollBarInfo(richTextBox.Handle, OBJID_VSCROLL, ref psbi);
            if (psbi.rgstate[0] == 0) {
                GetScrollRange(richTextBox.Handle, SB_VERT, out nMin, out nMax);
                height = (nMax - nMin);
            }

            return height;
        }

You may need to modify above method to make it work as per your requirement... Make sure to send Rtf string as parameter to method not normal text and also make sure to assign available width and height to the Richtextbox variable in the method...

You can play with WordWrap depending on your requirement...

Bathineni
  • 3,436
  • 18
  • 25