Introduction
There seems to be three ways to do real time syntax coloring. Good, fast, and flicker-free. Pick any two. Matthew Hazlett did an article that covers "good and flicker-free", so I thought some people might find it useful to have simply "good and fast".
Background
Back in January, I worked on HTML syntax coloring. I was amazed by the lack of information on the subject in VB.NET. There was some in VB, but naturally, it didn't upgrade too well (nothing is ever easy). So, I had to make my own. Isn't that how things typically are? I've learned a lot from CodeProject, and would like to give back.
Using the code
The code is pretty much self-explanatory, but the idea behind it works something like this:
- Find the number of visible lines.
- For each visible line, color it.
Simple enough, eh?
Now, on to the actual code, the first subroutine that finds the number of visible lines is called ColorVisibleLines
and it looks something like this:
Public Sub ColorVisibleLines(ByVal rtb As RichTextBox)
Dim FirstLine As Integer = FirstVisibleLine()
Dim LastLine As Integer = LastVisibleLine()
Dim FirstVisibleChar As Integer
Dim i As Integer = FirstLine
If (FirstLine = 0) And (LastLine = 0) Then
Exit Sub
Else
While i < LastLine
FirstVisibleChar = GetCharFromLineIndex(FirstLine)
ColorLineNumber(rtb, FirstLine, FirstVisibleChar)
FirstLine += 1
i += 1
End While
End If
End Sub
As you will notice, this sub calls another sub to do all the actual coloring for us.
Public Sub ColorLineNumber(ByVal rtb As RichTextBox, _
ByVal LineIndex As Integer, ByVal lStart As Integer)
Dim Line As String = rtb.Lines(LineIndex).ToLower
Dim i As Integer = 0
Dim Instance As Integer
Dim SelectionAt As Integer = rtb.SelectionStart
LockWindowUpdate(rtb.Handle.ToInt32)
rtb.SelectionStart = lStart
rtb.SelectionLength = Line.Length
rtb.SelectionColor = Color.Black
Instance = InStr(Line, "'")
If Instance <> 0 Then
rtb.SelectionStart = (lStart + Instance - 1)
rtb.SelectionLength = (Line.Length - Instance + 1)
rtb.SelectionColor = Color.Green
End If
If Instance = 1 Then
rtb.SelectionStart = SelectionAt
rtb.SelectionLength = 0
LockWindowUpdate(0)
Exit Sub
End If
While i < Words.Length
Instance = InStr(Line, Words(i).Word)
If Instance <> 0 Then
rtb.SelectionStart = (lStart + Instance - 1)
rtb.SelectionLength = Words(i).Word.Length
rtb.SelectionColor = Words(i).Color
End If
i += 1
End While
rtb.SelectionStart = SelectionAt
rtb.SelectionLength = 0
LockWindowUpdate(0)
End Sub
The keywords to be colored are stored in a structure called KeyWords
which holds the string to color, and the color to color the string.
Closing
All in all, it's not the most efficient way to color things. For example, you may have noticed that the Instr
function is used to locate the keywords. Regular Expressions (or RegEx) could be used in lieu of the method currently implemented.
Another downside to this method is flicker. This is a very difficult issue to overcome. Even with the LockWindowUpdate
API function, it still flickers (go figure). I am currently attempting to make a non-inherited RichTextBox
that will be a clone of Visual Studio's editor. However, it's still a long distance from completion. The control will be free and I'll post it on CodeProject, and it will contain a lot of features such as line numbering, breakpoints, brace-matching, expanding-collapsing regions, and best of all good, fast, and flicker-free real time syntax coloring.