Measure String inside RichTextBox Control

2019-01-26 08:13发布

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条回答
▲ chillily
2楼-- · 2019-01-26 08:29

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;
查看更多
叛逆
3楼-- · 2019-01-26 08:34

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.

查看更多
看我几分像从前
4楼-- · 2019-01-26 08:41

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...

查看更多
▲ chillily
5楼-- · 2019-01-26 08:42

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
查看更多
混吃等死
6楼-- · 2019-01-26 08:49

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.

查看更多
再贱就再见
7楼-- · 2019-01-26 08:54

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))
查看更多
登录 后发表回答