简体   繁体   中英

Autoscaling RichTextBox

I am trying to use read-only RichTextBoxes to show user-generated text. The height of the textbox and control should depend on the content and be limited to a certain maximum, anything past that point uses scroll bars.

AutoSize does not appear to work for RTB's

public void Rescale()
{
    Point pt = rtbComment.GetPositionFromCharIndex(rtbComment.Text.Length);
    int height = rtbComment.GetPositionFromCharIndex(rtbComment.Text.Length).Y + (int)rtbComment.SelectionFont.GetHeight();
    if (height > 250)
        height = 250;
    this.Size = new System.Drawing.Size(616, height + 50);
    rtbComment.Size = new System.Drawing.Size(614, height);
}

This works absolutely fine for short comments or comments with little text and many linebreaks, but for long one-liners that are broken into ~4 lines, the point I get from GetPositionFromCharIndex is all wrong - the function puts it somewhere at 105px down on the y-Axis when it's actually closer to 60, making the textbox about twice as big as it's supposed to be.

The width does not appear to be the issue here, as the box starts with the width I am setting it to and reading the point out again produces the same result.

Solved.

I used the TextRenderer.MeasureText method.

Since this method ignores the fact that very long lines will receive one or more automated linebreaks in the RichTextBox, I've written a function that manually splits the text into lines of any length by linebreaks, then measures each of these lines to check how many lines it'll use in the RTB.

Here's the function, in case anyone needs it:

public int getLines(string comment)
{
    int height_ln = 0;

    string[] lines;

    //split into lines based on linebreaks
    if (comment.Contains("\n"))
    {
        lines = comment.Split('\n');
    }
    else
    {
        lines = new string[1];
        lines[0] = comment;
    }

    //check each line to see if it'll receive automatic linebreaks
    foreach(string line in lines)
    {
        int text_width = TextRenderer.MeasureText(line, rtbKommentar.Font).Width;
        double text_lines_raw = (double)text_width / 1400; //1400 is the width of my RichTextBox

        int text_lines = 0;

        if (line.Contains("\r")) //Please don't call me out on this, I'm already feeling dirty
            text_lines = (int)Math.Floor(text_lines_raw);
        else
            text_lines = (int)Math.Ceiling(text_lines_raw);
        if (text_lines == 0)
            text_lines++;

        height_ln += text_lines;
    }
    return height_ln; //this is the number of lines required, to adjust the height of the RichTextBox I need to multiply it by 15, which is the font's height.
}

The WinForm RichtextBox exposes the ContentsResized Event that when coupled with the MinimumSize Property and the MaximumSize Property allows for a auto-sized control.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        rtbComment.MinimumSize = new Size(250, 200);
        rtbComment.MaximumSize = new Size(250, 400);
        rtbComment.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical;
        rtbComment.ContentsResized += rtbComment_ContentResized;

    }

    private void rtbComment_ContentResized(object sender, ContentsResizedEventArgs e)
    {
        rtbComment.Size = e.NewRectangle.Size;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM