2012-08-14 4 views
-1

입력 텍스트에 특정 구문의 색상을 지정하는 RichTextBox를 만듭니다. TextBox에 타이핑하거나 많은 양의 텍스트를 붙여 넣거나 많은 양의 텍스트를 스크롤 할 때 아무런 문제가 없습니다.C#, RichTextBox 프로세싱 라인

다른 사람이 텍스트 상자에 붙여 넣은 후에 ProcessAllLines 함수를 호출하면이 함수는 각 행을 처리하고 내가 정의한대로 적절한 문자를 색칠 할 때 문제가 발생합니다. 스레드로 백그라운드에서이 작업을 수행 할 수있는 방법이 있습니까? 그리고 지금까지 색상이 지정된 텍스트를 스크롤 할 수 있습니까?

붙여 넣은 텍스트의 색상을 빠르게 할 수있는 다른 방법은 없나요?

코드 :

protected override void WndProc(ref System.Windows.Forms.Message m) 
    { 
     if (m.Msg == 0x0f) 
     { 
      if (m_bPaint) 
       base.WndProc(ref m); 
      else 
       m.Result = IntPtr.Zero; 
     } 
     else 
      base.WndProc(ref m); 
    } 

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 
    { 
     if((keyData == (Keys.Control | Keys.V))) 
     { 
      Console.WriteLine("Pasted!"); 
      ProcessAllLines(); 
      return base.ProcessCmdKey(ref msg, keyData); 
     } 
     else 
     { 
      return base.ProcessCmdKey(ref msg, keyData); 
     } 
    } 

    protected override void OnTextChanged(EventArgs e) 
    { 
     if (m_bTxtChgOk) 
     { 
      // Calculate stuff here. 
      m_nContentLength = this.TextLength; 

      int nCurrentSelectionStart = SelectionStart; 
      int nCurrentSelectionLength = SelectionLength; 

      m_bPaint = false; 

      // Find the start of the current line. 
      m_nLineStart = nCurrentSelectionStart; 
      while ((m_nLineStart > 0) && (Text[m_nLineStart - 1] != '\n')) 
       m_nLineStart--; 

      // Find the end of the current line. 
      m_nLineEnd = nCurrentSelectionStart; 
      while ((m_nLineEnd < Text.Length) && (Text[m_nLineEnd] != '\n')) 
       m_nLineEnd++; 

      // Calculate the length of the line. 
      m_nLineLength = m_nLineEnd - m_nLineStart; 

      // Get the current line. 
      m_strLine = Text.Substring(m_nLineStart, m_nLineLength); 

      // Process this line. 
      ProcessLine(); 

      m_bPaint = true; 
     } 
    } 

    public void ProcessAllLines() 
    { 
     m_bPaint = false; 
     m_bTxtChgOk = false; 

     int nStartPos = 0; 
     int i = 0; 
     int nOriginalPos = SelectionStart; 
     while (i < Lines.Length) 
     { 
      m_strLine = Lines[i]; 
      m_nLineStart = nStartPos; 
      m_nLineEnd = m_nLineStart + m_strLine.Length; 
      m_nLineLength = m_nLineEnd - m_nLineStart; 

      ProcessLine(); 
      i++; 

      nStartPos += m_strLine.Length + 1; 
     } 
     SelectionStart = nOriginalPos; 

     m_bPaint = true; 
     m_bTxtChgOk = true; 
    } 


    private void ProcessLine() 
    { 
     // Save the position 
     int nPosition = SelectionStart; 
     // Next three code lines turn the whole current line to black text to begin with 
     SelectionStart = m_nLineStart; 
     SelectionLength = m_nLineLength; 
     SelectionColor = Color.Black; 

     // Get us a copy of the current line to play around with 
     String lcpy_strLine = new String(m_strLine.ToCharArray()); 
     // Make it uppercase so we dont have to look for "upper" and "LOWER" cases 
     lcpy_strLine = lcpy_strLine.ToUpper(); 

     // Make each letter green first, then we can change its color later. 
     int x = 0; 
     while (x < m_nLineLength) 
     { 
      if (Char.IsLetter(lcpy_strLine[x]) || lcpy_strLine[x].Equals('\\')) 
      { 
       SelectionStart = m_nLineStart + x; 
       SelectionLength = 1; 
       SelectionColor = Color.Green; 
      } 
      x++; 
     } 

     // These color from the specified char until a non-num is encountered 
     lcpy_strLine = ColorTilNoNumFromChar(":", "~", Color.DarkBlue, lcpy_strLine); 
     lcpy_strLine = ColorTilNoNumFromChar("M", "m", Color.Red, lcpy_strLine); 
     lcpy_strLine = ColorTilNoNumFromChar("N", "n", Color.Maroon, lcpy_strLine); 
     lcpy_strLine = ColorTilNoNumFromChar("G", "g", Color.Blue, lcpy_strLine); 

     //These color this char is not followed by a letter && !(a num || a symbol) 
     lcpy_strLine = ColorCharIfNotFollowedByLetter("X", Color.Green, lcpy_strLine); 
     lcpy_strLine = ColorCharIfNotFollowedByLetter("Y", Color.Green, lcpy_strLine); 
     lcpy_strLine = ColorCharIfNotFollowedByLetter("Z", Color.Green, lcpy_strLine); 

     // Make sure #11.11=11.11 is blue where 1 is a number and . are optional 
     while (m_nLineLength >= 3 && 
      lcpy_strLine.Contains("#") && lcpy_strLine.Contains("=") && 
      lcpy_strLine.IndexOf('#') < lcpy_strLine.IndexOf('=')) 
     { 
      int j = 0; 
      int indx1 = lcpy_strLine.IndexOf("#"); 
      int indx2 = lcpy_strLine.IndexOf('='); 
      for (j = indx1 + 1; j < m_nLineLength; j++) 
       if (!Char.IsDigit(lcpy_strLine[j]) && !lcpy_strLine[j].Equals('.')) 
        break; 
      if (lcpy_strLine[j].Equals('=') && !lcpy_strLine[j - 1].Equals('#')) 
      { 
       for (j = j + 1; j < m_nLineLength; j++) 
        if (!Char.IsDigit(lcpy_strLine[j]) && !lcpy_strLine[j].Equals('.')) 
         break; 
       SelectionStart = m_nLineStart + indx1; 
       SelectionLength = j - indx1; 
       SelectionColor = Color.Blue; 
      } 
      lcpy_strLine = CopyOverAtIndex("~", indx1, lcpy_strLine); 
      lcpy_strLine = CopyOverAtIndex("~", indx2, lcpy_strLine); 
     } // endwhile 

     if (lcpy_strLine.Contains("P")) 
     { 
      SelectionStart = m_nLineStart + lcpy_strLine.IndexOf('P') + 1; 
      SelectionLength = m_nLineLength - lcpy_strLine.IndexOf('P'); 
      SelectionColor = Color.Black; 
     } 

     // These two are for [XXXXX] and Comments 
     lcpy_strLine = ColorInsideTwoChars("[", "]", Color.Black, lcpy_strLine); 
     lcpy_strLine = ColorInsideTwoChars("(", ")", Color.Purple, lcpy_strLine); 

     //This is for single quote comments 
     if (lcpy_strLine.Contains("'")) 
     { 
      SelectionStart = m_nLineStart + lcpy_strLine.IndexOf('\''); 
      SelectionLength = m_nLineLength - lcpy_strLine.IndexOf('\''); 
      SelectionColor = Color.Purple; 
     } 

     // Set the postion to the saved position 
     SelectionStart = nPosition; 
     SelectionLength = 0; 
     SelectionColor = Color.Black; 
    } 

    private String ColorInsideTwoChars(String car1, String car2, Color clr, String lineRef) 
    { 
     while ((lineRef.Contains(car1) && lineRef.Contains(car2)) && 
      lineRef.IndexOf(car1) < lineRef.IndexOf(car2)) 
     { 
      int indx1 = lineRef.IndexOf(car1); 
      int indx2 = lineRef.IndexOf(car2); 
      SelectionStart = m_nLineStart + indx1; 
      SelectionLength = (indx2 - indx1) + 1; 
      SelectionColor = clr; 
      lineRef = CopyOverAtIndex("~", indx1, lineRef); 
      lineRef = CopyOverAtIndex("~", indx2, lineRef); 
     } 
     return lineRef; 
    } 
    private String ColorTilNoNumFromChar(String car, String rplcar, Color clr, String lineRef) 
    { 
     while (lineRef.Contains(car)) 
     { 
      int j = 0; 
      int indx1 = lineRef.IndexOf(car); 
      for (j = indx1 + 1; j < m_nLineLength; j++) 
      { 
       if (!Char.IsDigit(lineRef[j])) 
        break; 
      } 
      SelectionStart = m_nLineStart + indx1; 
      SelectionLength = j - indx1; 
      SelectionColor = clr; 
      lineRef = CopyOverAtIndex(rplcar, indx1, lineRef); 
     } 
     return lineRef; 
    } 
    private String ColorCharIfNotFollowedByLetter(String car, Color clr, String lineRef) 
    { 
     while (lineRef.Contains(car) && 
      (lineRef.IndexOf(car) + 1 < m_nLineLength)) 
     { 
      int indx1 = lineRef.IndexOf(car); 
      SelectionStart = m_nLineStart + indx1; 
      SelectionLength = 1; 
      if (!Char.IsLetter(lineRef[lineRef.IndexOf(car) + 1])) 
       SelectionColor = clr; 
      else 
       SelectionColor = Color.Black; 
      lineRef = CopyOverAtIndex("~", indx1, lineRef); 
     } 
     return lineRef; 
    } 
    private String CopyOverAtIndex(String car, int index, String refStr) 
    { 
     return refStr.Remove(index, 1).Insert(index, car); 
    } 

답변

1

는 시작이 시도 :

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 
    { 
     if ((keyData == (Keys.Control | Keys.V))) 
     { 
      Debug.WriteLine("Pasted!"); 
      this.SuspendLayout(); 
      ProcessAllLines(); 
      this.ResumeLayout(); 
      return base.ProcessCmdKey(ref msg, keyData); 
     } 
     else 
     { 
      return base.ProcessCmdKey(ref msg, keyData); 
     } 
    } 
나는 또한이 라인

String lcpy_strLine = new String(m_strLine.ToCharArray()); 

을 변경하여 ProcessLine에서 코드를 리팩토링 권합니다

char[] lcpy_strLine = m_strLine.ToUpper().ToCharArray(); 

그리고 거기에서부터 진행하십시오. 토큰을 거의 한 번 호출 할 때마다 장기간에 걸쳐 메모리 부담이 될 새로운 줄 문자열이 생성됩니다.