onsdag 8 april 2009

DEVTIPS #16 Göra Syntax Highlight med RichTextBox utan flicker!



1) Skapa en klass som ärver av RichTextBox overrida WndProc för att äta en del paint messages (Hemligheten för att slippa flicker). I OnTextChanged eventet kan vi då styra när kontrollen skall ritas om genom att sätta m_bPaint.

    public class SyntaxRichTextBox : System.Windows.Forms.RichTextBox {

        private bool m_bDoEvents = true;
        private static bool m_bPaint = true;
        private string[] m_Keywords = new string[] { 
                                                     "require", "and", "break", "false", 
                                                     "in", "local", "nil", "not", "or", 
                                                     "return", "true", "do", "else", "elseif", 
                                                     "end", "for", "function", "if", "repeat", 
                                                     "then", "until", "while"
                                                   };


        protected override void WndProc(ref System.Windows.Forms.Message m) {
            // Tar bort flicker från RichTextBox
            if (m.Msg == 0x00f) {
                if (m_bPaint)
                    base.WndProc(ref m);
                else
                    m.Result = IntPtr.Zero;
            } else
                base.WndProc(ref m);
        }

        public SyntaxRichTextBox() {
        }

        protected override void OnKeyDown(KeyEventArgs e) {
            base.OnKeyDown(e);
        }

        protected override void OnTextChanged(EventArgs e) {
            if (m_bDoEvents == true) {
                m_bPaint = false;
                try {
                    int iCharIndex = GetFirstCharIndexOfCurrentLine();
                    int iLine = GetLineFromCharIndex(iCharIndex);
                    int iLength = Lines[iLine].Length;
                    SyntaxHighlight(iCharIndex, iLength);
                } catch {
                }
                m_bPaint = true;
            }
            base.OnTextChanged(e);
        }

        private void FindKeyWord(string sKeyword, Color oColor, int iCharIndex, int iLength) {
            int iIndex = Find(sKeyword, iCharIndex, (iCharIndex + iLength), RichTextBoxFinds.MatchCase | RichTextBoxFinds.WholeWord);
            while (iIndex >= 0) {
                SelectionColor = oColor;
                if ((iIndex + sKeyword.Length) < (iCharIndex + iLength)) {
                    iIndex = Find(sKeyword, iIndex + sKeyword.Length, (iCharIndex + iLength), RichTextBoxFinds.MatchCase | RichTextBoxFinds.WholeWord);
                } else {
                    break;
                }
            }
        }

        public void Initialize() {
            m_bDoEvents = false;
            for (int i = 0; i <>
                int chfi = GetFirstCharIndexFromLine(i);
                SyntaxHighlight(chfi, Lines[i].Length);
            }
            m_bDoEvents = true;
        }

        private void SyntaxHighlight(int iCharIndex, int iLength) {
            int index = iCharIndex;
            int length = iLength;
            int iCursorPos = SelectionStart;

            SelectionStart = iCharIndex;
            SelectionLength = iLength;
            SelectionColor = Color.Black;

            foreach (string sKeyword in m_Keywords) {
                FindKeyWord(sKeyword, Color.Blue, iCharIndex, iLength);
            }

            SelectionStart = index;
            SelectionLength = length;
            // find numbers
            Regex rNum = new Regex("[0-9]*");
            Match mNum = rNum.Match(SelectedText);
            while (mNum.Success) {
                if (mNum.Captures.Count > 0) {
                    string sExp = mNum.Captures[0].Value;
                    FindKeyWord(sExp, Color.DarkOrchid, iCharIndex, iLength);
                }
                mNum = mNum.NextMatch();
            }

            SelectionStart = index;
            SelectionLength = length;
            // find xml
            Regex rXml = new Regex("<[^>]*>");
            Match mXml = rXml.Match(SelectedText);
            while (mXml.Success) {
                if (mXml.Captures.Count > 0) {
                    string sExp = mXml.Captures[0].Value;
                    FindKeyWord(sExp, Color.MediumSlateBlue, iCharIndex, iLength);
                }
                mXml = mXml.NextMatch();
            }       

            // reset
            SelectionStart = iCursorPos;
            SelectionLength = 0;
            SelectionColor = Color.Black;
        }

    }

2) Användning:
         SyntaxRichTextBox srt = new SyntaxRichTextBox();
            this.Controls.Add(srt);
            srt.Dock = DockStyle.Fill;

Inga kommentarer: