-1

入力テキストの特定の構文に色を付ける RichTextBox を作成しています。TextBox に入力したり、大量のテキストを貼り付けたり、大量のテキストをスクロールしたりするときに問題はありません。

私の問題は、誰かがテキストボックスに貼り付けた後に関数 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);
    }
4

1 に答える 1

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

この行を変更して、ProcessLine のコードをリファクタリングすることもお勧めします。

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

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

そしてそこから進みます。トークンのほぼすべての呼び出しで、行文字列の新しいコピーを取得しますが、これは長期的にはメモリの負担になります。

于 2012-08-14T20:43:43.517 に答える