在RichTextBox控件中测量字符串长度

11

请问如何测量richtextbox控件中字符串的大小,以便根据其内容自动调整rich textbox控件的大小?

谢谢。

编辑:

我已经考虑过了,由于下面的答案无法处理RichTextBox控件中存在不同字体的情况,那么如果我可以获取richtextbox控件的左上坐标,然后获取最后一行文本的右下坐标,这将基本上给出RichTextBox控件中字符串的宽度和高度。这是可能的吗?还是这样做是个坏主意?

6个回答

7
将以下代码放在 ContentsResized 事件中:
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

ContentsResizede.NewRectangle对我很有帮助。其他常见的方法,如AutoSizeGetPreferredSize似乎不能很好地适用于RichTextBox - Ben Challenor
这个不起作用。高度最终太短了,即使我修改它以设置sender.Width = w,宽度也根本没有改变。 - Nick

3
假设有人在控制器中输入内容,您可以使用事件,在每次输入一个字符时触发(增加计数器),并在删除时减少。这将给您一个真实的计数。
编辑:
您尝试过使用此方法来调整高度吗?
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;

或者您可以使用宽度来实现:

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

SizeF f = g.MeasureString(richTextBox1.Text, richTextBox1.Font);
richTextBox1.Width = (int)(f.Width)+5;

这是我目前正在做的事情,尽管你不能用这种方式考虑字体样式/大小,最终rtb将无法跟上,文本会溢出。 - anon271334
不是针对你,但这样做会产生非常丑陋的结果。一定有一种方法可以做到这一点,而不会让 RichTextBox 看起来像要从我的显示器中爆炸出来。 - anon271334
嗯,这里似乎运行得很好,但我没有应用任何字体样式。 - user195488
这可能适用于简单的文本框,但对于可以具有粗体字、多种字体和多种字号的RichTextBoxes无效。 - Nick

3
尝试调用GetPreferredSize(Size.Empty)。它在Control类中定义,如果被RichTextBoxControl属性覆盖,则应该能够给您所需的内容。
如果您传入的不是Size.Empty,那么它将使用该值作为最大限制。使用Size.Empty意味着潜在大小不受限制。

你甚至可以使用宽度 GetPreferredSize(new Size(width, 0)) 来调用它,然后从返回的 Size 中获取高度。 - Rémi
这个不起作用。GetPerferredSize返回的高度和宽度都太短了。 - Nick

0

我找到了解决富文本框高度问题的方法... 我已经修改了它以供通用使用...

在您的应用程序中创建以下结构体....

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

在您的类中为表单创建以下私有变量(无论何时需要计算富文本高度):
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);

请在您的类中添加以下方法以用于表单:

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

您可能需要修改上述方法以使其按照您的要求工作... 确保将Rtf字符串作为参数发送到方法中,而不是普通文本,并确保在方法中将可用的宽度和高度分配给Richtextbox变量...

根据您的需求可以调整WordWrap...


这个不行。高度总是太短了。 - Nick

0

补充一下bathineni的好答案:

背景:我需要测量RTF输出高度以便渲染到纸上,因为我有自定义动态页面页眉/页脚,所以我需要控制分页)。

(由于复杂的RTF,包括带换行符的行和多列表格,RichTextBox.GetLineFromCharIndex让我失望了。)

总之,一切都很顺利,直到有人使用我的应用程序时出现了可怕的Windows“使文本和其他项目变大或变小”(DPI设置)。简而言之,现在测量更大字体大小时,它会破坏页面长度计算。(打印机仍然正确地呈现文本和列 - 只是页面长度现在全部错误。)

只考虑DPI差异失败了,因为简而言之,更大的文本无法正确适合源RTF tx和cellx值。

总之,如果其他人正在做类似疯狂的事情,经过一些试错,我得出了以下(最终非常少的)修改bathineni CalculateRichTextHeight方法的结论:

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.

看起来原本不起眼的Control.Scale(sizef)居然有用处。

注意:如果将结果转换为实际打印行(在我的情况下,所有的\pard都是“\sl-240\slmult0”,每行大约16个像素),也要记得重新调整除数。 例如,在我的情况下:

lines = height / (int)(16 * (dpix / 96))

0

您可以通过调用TextRenderer.MeasureText来测量字符串。

但是,如果文本包含多种字体,则此方法将无法正常工作。

编辑:您需要使用GetPositionFromCharIndex方法。
请注意,如果有多行文本,您应该取每行最后一个字符的X坐标的最大值。


谢谢。我不太理解那个页面。它为什么要绘制文本?是否可以只返回一个宽度和高度值,以便我可以将 RichTextBox 的大小重置为新的大小? - anon271334
TextRenderer.MeasureText并дёҚдјҡз»ҳеҲ¶д»»дҪ•дёңиҘҝпјҢе®ғеҸӘжҳҜиҝ”еӣһж–Үжң¬еңЁеғҸзҙ дёӯзҡ„еӨ§е°ҸгҖӮ - SLaks

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接