Как обрезать строку, чтобы поместиться в контейнер?

есть много вопросов (например:1, 2, 3, 4, 5) с просьбой как можно обрезать строку до нужного количества символов. Но я хочу, чтобы фрагмент текста был усечен, чтобы поместиться в контейнер. (IE: обрезать строку по ширине в пиксели, не символов).

Это легко, если вы используете WPF, но не так много в WinForms...

Так: как вы можете обрезать струну, чтобы она поместилась в контейнер?

2 ответов


после дня кодирования я нашел решение, и я хотел поделиться им с сообществом.

прежде всего:нет собственной функции усечения для строки или текстового поля winforms. При использовании метки можно использовать свойство AutoEllipsis.

FYI: многоточие-это знак препинания, состоящий из трех точек. IE:...

вот почему я сделал это:

public static class Extensions
{
    /// <summary>
    /// Truncates the TextBox.Text property so it will fit in the TextBox. 
    /// </summary>
    static public void Truncate(this TextBox textBox)
    {
        //Determine direction of truncation
        bool direction = false;
        if (textBox.TextAlign == HorizontalAlignment.Right) direction = true;

        //Get text
        string truncatedText = textBox.Text;

        //Truncate text
        truncatedText = truncatedText.Truncate(textBox.Font, textBox.Width, direction);

        //If text truncated
        if (truncatedText != textBox.Text)
        {
            //Set textBox text
            textBox.Text = truncatedText;

            //After setting the text, the cursor position changes. Here we set the location of the cursor manually.
            //First we determine the position, the default value applies to direction = left.

            //This position is when the cursor needs to be behind the last char. (Example:"…My Text|");
            int position = 0;

            //If the truncation direction is to the right the position should be before the ellipsis
            if (!direction)
            {
                //This position is when the cursor needs to be before the last char (which would be the ellipsis). (Example:"My Text|…");
                position = 1; 
            }

            //Set the cursor position
            textBox.Select(textBox.Text.Length - position, 0);
        }
    }

    /// <summary>
    /// Truncates the string to be smaller than the desired width.
    /// </summary>
    /// <param name="font">The font used to determine the size of the string.</param>
    /// <param name="width">The maximum size the string should be after truncating.</param>
    /// <param name="direction">The direction of the truncation. True for left (…ext), False for right(Tex…).</param>
    static public string Truncate(this string text, Font font, int width, bool direction)
    {
        string truncatedText, returnText;
        int charIndex = 0;
        bool truncated = false;
        //When the user is typing and the truncation happens in a TextChanged event, already typed text could get lost.
        //Example: Imagine that the string "Hello Worl" would truncate if we add 'd'. Depending on the font the output 
        //could be: "Hello Wor…" (notice the 'l' is missing). This is an undesired effect.
        //To prevent this from happening the ellipsis is included in the initial sizecheck.
        //At this point, the direction is not important so we place ellipsis behind the text.
        truncatedText = text + "…";

        //Get the size of the string in pixels.
        SizeF size = MeasureString(truncatedText, font);

        //Do while the string is bigger than the desired width.
        while (size.Width > width)
        {
            //Go to next char
            charIndex++;

            //If the character index is larger than or equal to the length of the text, the truncation is unachievable.
            if (charIndex >= text.Length)
            {
                //Truncation is unachievable!

                //Throw exception so the user knows what's going on.
                throw new IndexOutOfRangeException("The desired width of the string is too small to truncate to.");
            }
            else
            {
                //Truncation is still applicable!

                //Raise the flag, indicating that text is truncated.
                truncated = true;

                //Check which way to text should be truncated to, then remove one char and add an ellipsis.
                if (direction)
                {
                    //Truncate to the left. Add ellipsis and remove from the left.
                    truncatedText = "…" + text.Substring(charIndex);
                }
                else
                {
                    //Truncate to the right. Remove from the right and add the ellipsis.
                    truncatedText = text.Substring(0, text.Length - charIndex) + "…";
                }

                //Measure the string again.
                size = MeasureString(truncatedText, font);
            }
        }

        //If the text got truncated, change the return value to the truncated text.
        if (truncated) returnText = truncatedText;
        else returnText = text;

        //Return the desired text.
        return returnText;
    }

    /// <summary>
    /// Measures the size of this string object.
    /// </summary>
    /// <param name="text">The string that will be measured.</param>
    /// <param name="font">The font that will be used to measure to size of the string.</param>
    /// <returns>A SizeF object containing the height and size of the string.</returns>
    static private SizeF MeasureString(String text, Font font)
    {
        //To measure the string we use the Graphics.MeasureString function, which is a method that can be called from a PaintEventArgs instance.
        //To call the constructor of the PaintEventArgs class, we must pass a Graphics object. We'll use a PictureBox object to achieve this. 
        PictureBox pb = new PictureBox();

        //Create the PaintEventArgs with the correct parameters.
        PaintEventArgs pea = new PaintEventArgs(pb.CreateGraphics(), new System.Drawing.Rectangle());
        pea.Graphics.PageUnit = GraphicsUnit.Pixel;
        pea.Graphics.PageScale = 1;

        //Call the MeasureString method. This methods calculates what the height and width of a string would be, given the specified font.
        SizeF size = pea.Graphics.MeasureString(text, font);

        //Return the SizeF object.
        return size;
    }
}

использование: Это класс, который можно скопировать и вставить в пространство имен, содержащее форму winforms. Убедитесь, что вы включили "использование системы.Рисование;"

этот класс имеет два метода расширений, оба называются Truncate. В принципе, теперь вы можете сделать это:

public void textBox1_TextChanged(object sender, EventArgs e)
{
    textBox1.Truncate();
}

теперь вы можете ввести что-то в textBox1, и при необходимости он автоматически усечет вашу строку, чтобы вписаться в текстовое поле, и добавит многоточие.

описание: Этот класс В настоящее время содержит 3 метода:

  1. усечение (расширение для текстового поля)
  2. усечение (расширение для строки)
  3. MeasureString

усечение (расширение для текстового поля)

этот метод автоматически усекает текстовое поле.Свойство text. Направление усечения является задержкой свойством TextAlign. (Например: "усечение для левого выравнивания..."," ... ncation для правого выравнивания".) Пожалуйста, обратите внимание: этот метод может потребоваться некоторое изменение для работы с другими системами письма, такими как иврит или арабский.


усечение (расширение для строки)

для использования этого метода необходимо передать два параметра: шрифт и требуемую ширину. Шрифт используется для вычисления ширины строки, а желаемая ширина используется как максимальная ширина, разрешенная после усечения.


MeasureString

этот метод является частным в этом фрагменте кода. Поэтому, если вы хотите использовать его, вы должны сначала изменить его на public. Этот метод используется для измерения высоты и ширины строки в пикселях. Для этого требуется два параметра: измеряемый текст и шрифт текста.

надеюсь, я помог кому-то с этим. Возможно, есть другой способ сделать это, я нашел этой ответ Ганса на проходе, который усекает ToolTipStatusLabel, что довольно впечатляет. Мои навыки .NET далеки от навыков Ханса Пассанта, поэтому мне не удалось преобразовать этот код для работы с чем-то вроде текстового поля... Но если вам это удалось, или у вас есть другое решение, я хотел бы его увидеть! :)


я протестировал код Jordy и сравнил результат с этим моим кодом, нет никакой разницы, они оба обрезают/усекают довольно хорошо, но не хорошо в некоторых случаях, это может быть размер, измеренный MeasureString() не точным. Я знаю, что этот код-просто упрощенная версия, я размещаю его здесь, Если кто-то заботится об этом и использует его, потому что он короткий, и я тестировал: нет никакой разницы в том, как именно этот код может обрезать/усекать строку по сравнению с кодом Джорди, конечно, его код какой-то полной версии с 3 поддержанными методами.

public static class TextBoxExtension
{
    public static void Trim(this TextBox text){            
        string txt = text.Text;
        if (txt.Length == 0 || text.Width == 0) return;
        int i = txt.Length;            
        while (TextRenderer.MeasureText(txt + "...", text.Font).Width > text.Width)            
        {
            txt = text.Text.Substring(0, --i);
            if (i == 0) break;
        }
        text.Text = txt + "...";
    }
    //You can implement more methods such as receiving a string with font,... and returning the truncated/trimmed version.
 }