2013-07-15 42 views
7

Có rất nhiều câu hỏi (EG: 1, 2, 3, 4, 5) hỏi cách bạn có thể cắt ngắn chuỗi thành số ký tự mong muốn. Nhưng tôi muốn một đoạn văn bản cắt ngắn để vừa với một cái hộp. (IE: cắt chuỗi theo chiều rộng của nó trong pixel, không phải ký tự).Làm thế nào để cắt bớt một chuỗi để phù hợp trong một container?

Đây là dễ dàng nếu bạn sử dụng WPF, nhưng không quá nhiều trong WinForms ...

Vì vậy: cách có thể giúp bạn cắt một chuỗi để làm cho nó phù hợp trong một container?

Trả lời

13

Sau một ngày mã hóa, tôi đã tìm thấy giải pháp và tôi muốn chia sẻ nó với cộng đồng.

Trước hết: không có chức năng cắt ngắn gốc cho chuỗi hoặc hộp văn bản winforms. Nếu bạn sử dụng nhãn, bạn có thể sử dụng thuộc tính AutoEllipsis.

FYI: Một lược là một dấu chấm câu đó bao gồm ba dấu chấm. IE: ...

Đó là lý do tôi thực hiện điều này:

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

Cách sử dụng: Đây là một lớp học mà bạn có thể sao chép và dán trong không gian tên có chứa hình thức winforms của bạn. Đảm bảo bạn bao gồm "using System.Drawing;"

Lớp này có hai phương pháp tiện ích mở rộng, được gọi là Truncate. Về cơ bản, bây giờ bạn có thể làm điều này:

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

Bây giờ bạn có thể gõ một cái gì đó trong TextBox1 và nếu cần thiết, nó sẽ tự động cắt ngắn chuỗi của bạn để phù hợp trong hộp văn bản và nó sẽ thêm một dấu chấm lửng.

Tổng quan: lớp này hiện có 3 phương pháp:

  1. Truncate (phần mở rộng cho TextBox)
  2. Truncate (phần mở rộng cho string)
  3. MeasureString

Truncate (mở rộng cho TextBox)

Phương pháp này sẽ tự động cắt bớt thuộc tính TextBox.Text. Hướng cắt ngắn là sự ngăn chặn bởi thuộc tính TextAlign. (EG: "Cắt ngắn cho căn lề trái ...", "... ncation cho căn phải".) Xin lưu ý: phương pháp này có thể cần một số thay đổi để làm việc với các hệ thống viết khác như tiếng Do Thái hoặc tiếng Ả Rập.


Truncate (phần mở rộng cho string)

Để sử dụng phương pháp này bạn phải vượt qua hai tham số: một phông chữ và chiều rộng mong muốn. Phông chữ được sử dụng để tính chiều rộng của chuỗi và chiều rộng mong muốn được sử dụng làm chiều rộng tối đa cho phép sau khi cắt bớt.


MeasureString

Phương pháp này là tư nhân trong đoạn mã. Vì vậy, nếu bạn muốn sử dụng nó, trước tiên bạn phải thay đổi nó thành công khai. Phương pháp này được sử dụng để đo chiều cao và chiều rộng của chuỗi theo pixel. Nó đòi hỏi hai tham số: văn bản được đo và phông chữ của văn bản.

Tôi hy vọng tôi đã giúp ai đó với điều này. Có lẽ có một cách khác để thực hiện việc này, tôi đã tìm thấy this câu trả lời của Hans Passant, công cụ này cắt một ToolTipStatusLabel, điều này khá ấn tượng. Kỹ năng .NET của tôi không ở đâu gần Hans Passant nên tôi chưa quản lý để chuyển đổi mã đó để làm việc với một thứ gì đó giống như một TextBox ... Nhưng nếu bạn đã thành công, hoặc có một giải pháp khác, tôi rất thích nhìn thấy nó! :)

+1

+1 cho một số tài liệu đáng kinh ngạc về giải pháp của bạn. Tuy nhiên, cách tiếp cận này theo nghĩa đen thay đổi văn bản của 'TextBox'. Điều đó tất nhiên có thể được quản lý thông qua các thuộc tính khác như 'Tag' hoặc cái gì đó, nhưng câu trả lời của Hans chỉ ghi đè thủ tục' Paint'. Điều này để lại 'Text' một mình nhưng cung cấp cho người dùng với * illusion * rằng văn bản đã bị cắt ngắn. –

+0

@MichaelPerrenoud thực sự đáng chú ý. Và cũng là lý do tại sao tôi đề cập đến Hans Passants trả lời. Nó chỉ là thanh lịch hơn :) – Jordy

+1

Một lưu ý mặc dù, sau khi một số nghiên cứu, là bạn không thể thực sự tùy chỉnh vẽ bất cứ điều gì trên một hộp văn bản. Vì vậy, tôi sẽ nói với những gì bạn cần, bạn đã làm tốt nhất có thể. Công việc tuyệt vời! –

0

Tôi đã thử mã của Jordy và so sánh kết quả với mã này của tôi, không có sự khác biệt, cả hai đều cắt/cắt ngắn khá OK nhưng không tốt trong một số trường hợp, có thể là kích thước đo bằng MeasureString() không chính xác. Tôi biết mã này chỉ là một phiên bản đơn giản, tôi đăng nó ở đây nếu ai đó quan tâm đến nó và sử dụng nó vì nó ngắn và tôi đã thử nghiệm: không có sự khác biệt về cách mã này cắt/cắt chuỗi so với mã của Jordy, Tất nhiên mã của anh ấy là một loại phiên bản đầy đủ với 3 phương thức được hỗ trợ.

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. 
} 
Các vấn đề liên quan