2013-07-15 9 views
7

Ci sono un sacco di domande (EG: 1, 2, 3, 4, 5) chiedono come è possibile troncare una stringa in una quantità desiderata di caratteri. Ma voglio un pezzo di testo troncato per adattarlo a un contenitore. (IE: ritaglia la stringa in base alla larghezza in pixel, non caratteri).Come troncare una stringa per adattarla a un contenitore?

Questo è facile se si utilizza WPF, ma non così tanto in WinForms ...

Quindi: come si può troncare una stringa per farlo entrare in un contenitore?

risposta

13

Dopo una giornata di programmazione ho trovato una soluzione e volevo condividerla con la comunità.

Prima di tutto: non esiste una funzione di troncamento nativo per una casella di testo di stringhe o winform. Se si utilizza un'etichetta, è possibile utilizzare la proprietà AutoEllipsis.

FYI: I puntini di sospensione è un segno di punteggiatura che consistono di tre punti. IE: ...

Ecco perché ho fatto questo:

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

Usage: Questa è una classe è possibile copiare e incollare nel namespace che contiene il modulo di WinForms. Assicurati di includere "utilizzando System.Drawing;"

Questa classe ha due metodi di estensione, entrambi denominati Truncate. Fondamentalmente si può ora fare questo:

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

È ora possibile digitare qualcosa nel textBox1 e, se necessario, si troncherà automaticamente la stringa per adattarsi nella casella di testo e aggiungerà i puntini di sospensione.

Panoramica: Questa classe attualmente contiene 3 metodi:

  1. Tronca (estensione per TextBox)
  2. Tronca (estensione per archi)
  3. MeasureString

Tronca (estensione per TextBox)

Questo metodo tronca automaticamente la proprietà TextBox.Text. La direzione del troncamento è determinata dalla proprietà TextAlign. (EG: "Troncamento per allineamento a sinistra ...", "... ncation per allineamento a destra".) Nota: questo metodo potrebbe richiedere alcune modifiche per lavorare con altri sistemi di scrittura come l'ebraico o l'arabo.


troncatura (estensione per stringa)

Per utilizzare questo metodo è necessario passare due parametri: un font e una larghezza desiderata. Il carattere viene utilizzato per calcolare la larghezza della stringa e la larghezza desiderata viene utilizzata come larghezza massima consentita dopo il troncamento.


MeasureString

Questo metodo è privato nel frammento di codice. Quindi, se vuoi usarlo, devi prima cambiarlo in pubblico. Questo metodo viene utilizzato per misurare l'altezza e la larghezza della stringa in pixel. Richiede due parametri: il testo da misurare e il carattere del testo.

Spero di aver aiutato qualcuno con questo. Forse c'è un altro modo per farlo, ho trovato this risposta di Hans Passant, che tronca una ToolTipStatusLabel, che è piuttosto impressionante. Le mie competenze di .NET non sono neanche lontanamente simili a quelle di Hans Passant, quindi non sono riuscito a convertire quel codice per lavorare con qualcosa come un TextBox ... Ma se lo hai fatto, o se avessi un'altra soluzione mi piacerebbe vederlo! :)

+1

+1 per un'incredibile documentazione sulla soluzione. Ma questo approccio cambia letteralmente il testo di 'TextBox'. Ovviamente, ciò può essere gestito tramite altre proprietà come 'Tag' o qualcosa del genere, ma la risposta di Hans semplicemente sovrascrive la procedura' Paint'. Questo lascia il 'Text' da solo ma fornisce all'utente * l'illusione * che il testo sia stato troncato. –

+0

@MichaelPerrenoud che è davvero degno di nota. E anche la ragione per cui ho parlato di Hans Passants risponde. È solo più elegante :) – Jordy

+1

Una nota, dopo alcune ricerche, è che non si può davvero disegnare qualcosa su una casella di testo. Quindi direi con quello di cui hai bisogno, hai fatto il meglio che puoi. Lavoro fantastico! –

0

Ho testato il codice di Jordy e ho confrontato il risultato con questo mio codice, non c'è differenza, entrambi tagliano/troncano abbastanza bene ma in alcuni casi non è corretto, che potrebbe essere la dimensione misurata da MeasureString() non è esatto So che questo codice è solo una versione semplificata, lo metto qui se qualcuno se ne preoccupa e lo usa perché è breve e ho provato: non c'è differenza nel modo in cui esattamente questo codice può tagliare/troncare le stringhe rispetto al codice di Jordy, di Ovviamente il suo codice è una sorta di versione completa con 3 metodi supportati.

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. 
} 
Problemi correlati