如何确定一个字符串在指定宽度内的适合长度?

4
你好,我有一个问题需要调整文本的长度,以适应表单的长度。
在我的表单中,我放置了一个标签,负责显示一些长文本。但是,这个文本可能会非常长,无法适应表单。这就是为什么我想缩短这段文本并在末尾添加...的原因。
问题是,我不知道如何高效地计算最大长度的子字符串,以使其适合表单。到目前为止,我只能检查给定的文本是否太长(我使用Graphics类中的MeasureString方法)。
计算适合表单的最大子字符串的最佳方法是什么(子字符串的宽度小于form.Width)?

7
有一瞬间,我以为这是一个开玩笑的帖子,问一段绳子有多长... - Oded
7
也许你只需要设置 Label.AutoEllipsis 属性。 - Rob Kennedy
1
你必须考虑到字母的大小不同(在许多字体中,除了等宽字体):例如,'W'不像'i'那么小,因此通常不能假设一个单词具有相同数量的字母就具有相同的大小。 - Yet Another Geek
@Rob - 噢,闪亮!我今天学到了东西 :) - Oded
@Rob:谢谢,我错过了那个。 - Fredrik Mörk
显示剩余2条评论
5个回答

1

我有一个解决方案,因为我今天自己遇到了这个问题。我的ToolStripStatusLabel设置为自动调整大小,但它超出了父控件的宽度,因此隐藏了自己。我的解决方案专门用于ToolStripStatusLabel控件。由于这种情况下,该控件不提供MaxWidth属性或AutoEllipsis属性。它也不会为我生成Graphics对象,因为它不是控件家族的一部分。这种方法可以改变为使用两个Control对象,除了参数之外,没有太多变化。我的选择非常有限,所以我制造了这种方法:

/// <summary>
/// If a child ToolStripStatusLabel is wider than it's parent then this method will attempt to
/// make the child's text fit inside of the parent's boundaries. An ellipsis can be appended
/// at the end of the text to indicate that it has been truncated to fit.
/// </summary>
/// <param name="child">Child ToolStripStatusLabel</param>
/// <param name="parent">Parent control where the ToolStripStatusLabel resides</param>
/// <param name="appendEllipsis">Append an "..." to the end of the truncated text</param>
public static void TruncateChildTextAccordingToControlWidth(ToolStripStatusLabel child, Control parent, bool appendEllipsis)
{
    //If the child's width is greater than that of the parent's
    if(child.Size.Width > parent.Size.Width)
    {
        //Get the number of times that the child is oversized [child/parent]
        decimal decOverSized = (decimal)(child.Size.Width) / (decimal)(parent.Size.Width);

        //Get the new Text length based on the number of times that the child's width is oversized.
        int intNewLength = (int)(child.Text.Length / (2M * decOverSized)); //Doubling as a buffer (Magic Number).

        //If the ellipsis is to be appended
        if(appendEllipsis) //then 3 more characters need to be removed to make room for it.
            intNewLength = intNewLength - 3;

        //If the new length is negative for whatever reason
        if(intNewLength < 0) 
            intNewLength = 0; //Then default it to zero

        //Truncate the child's Text accordingly
        child.Text = child.Text.Substring(0, intNewLength);

        //If the ellipsis is to be appended
        if(appendEllipsis) //Then do this last
            child.Text += "...";
    }
}

我要首先指出的是,我犯了一个可怕的错误,包含了一个魔数!我很抱歉,但这个2M是一个缓冲区。目前我还找不到更好的方法来解决这个问题,如果我找到了,我一定会回来更新这里的内容。我需要这个魔数,因为我计算的百分比是准确的,但为了让子控件能够很好地适应父控件,我需要大约两倍于返回值的大小。

我相信这可能并不完全准确,取决于标签字体大小和其他因素,但这是一个开始的地方。


1

我知道的唯一可靠的方法是缩短你的字符串直到它适合,你可以使用MeasureString()来检查,不幸的是没有反向方法(给定一个宽度,这个字符串的多少会适合),所以你需要自己构建。


3
如果在该字符串上进行二分查找,那么确定它的哪个长度适合在表格中显示就不会太难。 - Gabe

1
我使用这段代码,通过从字符串开头删除字符来使我的状态栏文本适合。也许您可以根据自己的需要进行修改。
        status.Text = status.Text + " | " + newText;
        while (TextRenderer.MeasureText(status.Text, status.Font).Width > status.Width)
            status.Text = status.Text.Substring(1);

0

你可以逐字逐句地编写文本,并同时将光标移动到达到行末(表单的宽度)。我曾经遇到过类似的问题,但我是在表单上绘制文本,我改变了我的代码以适应你的需求。

private bool WriteWord(string word)
{
    Size size = TextRenderer.MeasureText(word + "  ", Font);
    if (cursor.X + size.Width > Width)
    {
        // you reached the end of the line
        return false;
    }
    label1.Text += word + "  "; // add the word to label.
    cursor.X += size.Width;
    return true;
}
Point Cursor;
private string FindMaxSubstring(string text)
{
    string[] tokens = text.Split(new string[] { " "}); 
    string substring ="";
    Cursor.X = 0;
    foreach (var t in tokens)
    {
        if (!string.IsNullOrEmpty(t.Trim()))
        {
            if (!WriteWord(t))
                return substring;
            substring += t;
        }
    }
}

0

将标签的AutoSize属性设置为true,然后将文本拆分为标记,并逐个将它们添加到label.Text中,直到label.Width > Width.


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