我创建了一个 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);
}