2013-07-15 8 views
7

Es gibt eine Menge Fragen (z. B. 1, 2, 3, 4, 5) fragt, wie Sie eine Zeichenfolge auf eine gewünschte Anzahl von Zeichen abgeschnitten können. Aber ich möchte, dass ein abgeschnittener Text in einen Container passt. (IE: Schneiden Sie die Zeichenfolge durch ihre Breite in Pixel, nicht Zeichen).Wie schneidet man eine Zeichenfolge ab, um in einen Container zu passen?

Dies ist einfach, wenn Sie WPF verwenden, aber in WinForms nicht so viel ...

Also: wie kann man gestutzt einen String in einen Behälter passen zu machen?

Antwort

13

Nach einem Tag der Codierung fand ich eine Lösung und ich wollte es mit der Gemeinschaft teilen.

Zunächst einmal: gibt es keine systemeigene truncate-Funktion für eine Zeichenfolge oder winforms TextBox. Wenn Sie ein Label verwenden, können Sie die AutoEllipsis-Eigenschaft verwenden.

FYI: Ein Auslassungszeichen ist ein Satzzeichen, das aus drei Punkten bestehen. IE: ...

Deshalb habe ich das gemacht:

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

Verbrauch: Dies ist eine Klasse, die Sie im Namensraum kopieren und einfügen können, die Ihre WinForms Form enthält. Stellen Sie sicher, dass Sie "using System.Drawing;"

enthalten Diese Klasse verfügt über zwei Erweiterungsmethoden, beide als Truncate bezeichnet. Grundsätzlich können Sie jetzt tun:

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

Sie können nun etwas in textBox1 geben und, wenn nötig, wird es automatisch abgeschnitten Zeichenfolge in der Textbox passen, und es wird ein Auslassungszeichen hinzuzufügen.

Übersicht: Diese Klasse umfasst derzeit drei Methoden:

  1. Truncate (Erweiterung für TextBox)
  2. Truncate (Erweiterung für string)
  3. MeasureString

Abschneiden (Erweiterung für TextBox)

Diese Methode wird die TextBox.Text-Eigenschaft automatisch abgeschnitten. Die Richtung der Kürzung wird durch die TextAlign-Eigenschaft bestimmt. (ZB: "Abschneiden für linkes Alignment ...", "... ncation für rechtes Alignment".) Bitte beachten Sie, dass diese Methode eventuell geändert werden muss, um mit anderen Schriftsystemen wie Hebräisch oder Arabisch zu arbeiten.


Kürzen (Erweiterung für string)

Um diese Methode zu verwenden, zwei Parameter übergeben müssen: eine Schriftart und eine gewünschte Breite. Die Schriftart wird verwendet, um die Breite der Zeichenfolge zu berechnen, und die gewünschte Breite wird als die maximal zulässige Breite nach dem Abschneiden verwendet.


Diese Methode ist privat im Code-Schnipsel MeasureString. Wenn Sie es also verwenden möchten, müssen Sie es zuerst in public ändern. Diese Methode wird verwendet, um die Höhe und Breite der Zeichenfolge in Pixel zu messen. Es benötigt zwei Parameter: den zu messenden Text und die Schriftart des Textes.

Ich hoffe, dass ich jemandem damit geholfen habe. Vielleicht gibt es einen anderen Weg, dies zu tun, fand ich this Antwort von Hans Passant, die eine ToolTipStatusLabel schneidet, die ziemlich beeindruckend ist. Meine .NET-Fähigkeiten sind bei weitem nicht die von Hans Passant, daher habe ich es nicht geschafft, diesen Code so zu konvertieren, dass er mit etwas wie einer TextBox funktioniert ... Aber wenn Sie Erfolg haben oder eine andere Lösung haben, würde ich es gerne sehen! :)

+1

+1 für einige unglaubliche Dokumentation zu Ihrer Lösung. Aber dieser Ansatz ändert buchstäblich den Text der 'TextBox'. Das kann natürlich über andere Eigenschaften wie "Tag" oder so gehandhabt werden, aber die Antwort von Hans überschreibt einfach die "Paint" -Prozedur. Dadurch bleibt der 'Text' in Ruhe, aber der Benutzer erhält die * Illusion *, dass der Text abgeschnitten wurde. –

+0

@MichaelPerrenoud das ist in der Tat bemerkenswert. Und auch der Grund, warum ich Hans Passants erwähnt habe. Es ist einfach eleganter :) – Jordy

+1

Eine Anmerkung, nach einigem Nachforschen ist, dass Sie wirklich nichts auf einer Textbox zeichnen können. Ich würde sagen, mit dem, was Sie brauchen, haben Sie das Beste getan, was Sie können. Fantastischer Job! –

0

ich den Code von Jordy getestet und das Ergebnis mit diesem Code von mir verglichen wird, gibt es keinen Unterschied, sie beide Trimm-/gestutzt ziemlich ok, aber nicht gut in einigen Fällen, dass die Größe von MeasureString() gemessen werden kann, ist nicht genau. Ich weiß, dass dieser Code nur eine vereinfachte Version ist, ich poste es hier, wenn jemand sich darum kümmert und es benutzt, weil es kurz ist und ich getestet habe: Es gibt keinen Unterschied wie genau dieser Code die Zeichenfolge im Vergleich zum Jordy-Code trimmen/trunkieren kann Natürlich ist sein Code eine Art Vollversion mit 3 unterstützten Methoden.

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. 
} 
Verwandte Themen