Quantcast
Channel: Chris Pietschmann - Win32API
Viewing all articles
Browse latest Browse all 6

VB.NET: Syntax Highlighting in a RichTextBox control

$
0
0

This last weekend I expirimented a little bit with extending the functionality of the RichTextBox control. Below you'll find an example of a small class that enherits from the RichTextBox control and allows you to implement syntax highlighting (with the use of a couple Win32 API call to smooth over the process of course.) The code pretty much speaks for itself.

 

PublicClass SyntaxRTB

   Inherits System.Windows.Forms.RichTextBox

   Private
DeclareFunction SendMessage Lib "user32" Alias "SendMessageA" _
      
(ByVal hWnd As IntPtr, ByVal wMsg AsInteger, ByVal wParam AsInteger, ByVal lParam AsInteger) AsInteger

 

 

   PrivateDeclareFunction LockWindowUpdate Lib "user32" (ByVal hWnd AsInteger) AsInteger

   Private _SyntaxHighlight_CaseSensitive AsBoolean = False

   Private Words AsNew DataTable

   'Contains Windows Messages for the SendMessage API call
   PrivateEnum EditMessages
      LineIndex = 187
      LineFromChar = 201
      GetFirstVisibleLine = 206
      CharFromPos = 215
      PosFromChar = 1062
   EndEnum

 

   ProtectedOverridesSub OnTextChanged(ByVal e As System.EventArgs)
      
ColorVisibleLines()
   
EndSub

 

   PublicSub ColorRtb()
      
Dim FirstVisibleChar AsInteger
      
Dim i AsInteger = 0

      
While i < Me.Lines.Length
         FirstVisibleChar = GetCharFromLineIndex(i)
         ColorLineNumber(i, FirstVisibleChar)
         i += 1
      EndWhile
   
EndSub

 

   PublicSub ColorVisibleLines()
      
Dim FirstLine AsInteger = FirstVisibleLine()
      Dim LastLine AsInteger = LastVisibleLine()
      Dim FirstVisibleChar AsInteger

      
If (FirstLine = 0) And (LastLine = 0) Then
         
'If there is no text it will error, so exit the sub
         
ExitSub
      
Else
         While FirstLine < LastLine
            FirstVisibleChar = GetCharFromLineIndex(FirstLine)
            ColorLineNumber(FirstLine, FirstVisibleChar)
            FirstLine += 1
         
EndWhile
      
EndIf

   
EndSub

 

   PublicSub ColorLineNumber(ByVal LineIndex AsInteger, ByVal lStart AsInteger)
      
Dim i AsInteger = 0
      
Dim Instance AsInteger
      
Dim LeadingChar, TrailingChar AsString
      
Dim SelectionAt AsInteger = Me.SelectionStart
      
Dim MyRow As DataRow
      
Dim Line() AsString, MyI AsInteger, MyStr AsString

      
' Lock the update
      
LockWindowUpdate(Me.Handle.ToInt32)

      MyI = lStart

      
If CaseSensitive Then
         
Line = Split(Me.Lines(LineIndex).ToString, " ")
      
Else
         
Line = Split(Me.Lines(LineIndex).ToLower, " ")
      
EndIf

      
ForEach MyStr In Line
         
Me.SelectionStart = MyI
         Me.SelectionLength = MyStr.Length

         
If Words.Rows.Contains(MyStr) Then
            
MyRow = Words.Rows.Find(MyStr)
            
If (Not CaseSensitive) Or (CaseSensitive And MyRow("Word") = MyStr) Then
               
Me.SelectionColor = Color.FromName(MyRow("Color"))
            
EndIf
         Else
            
Me.SelectionColor = Color.Black
         
EndIf

         
MyI += MyStr.Length + 1
      Next

      ' Restore the selectionstart
      
Me.SelectionStart = SelectionAt
      
Me.SelectionLength = 0
      
Me.SelectionColor = Color.Black

      
' Unlock the update
      
LockWindowUpdate(0)
   
EndSub

 

   PublicFunction GetCharFromLineIndex(ByVal LineIndex AsInteger) AsInteger
      
Return SendMessage(Me.Handle, EditMessages.LineIndex, LineIndex, 0)
   
EndFunction

 

   PublicFunction FirstVisibleLine() AsInteger
      
Return SendMessage(Me.Handle, EditMessages.GetFirstVisibleLine, 0, 0)
   
EndFunction

 

   PublicFunction LastVisibleLine() AsInteger
      
Dim LastLine AsInteger = FirstVisibleLine() + (Me.Height / Me.Font.Height)

      
If LastLine > Me.Lines.Length Or LastLine = 0 Then
         
LastLine = Me.Lines.Length
      EndIf

      
Return LastLine
   
EndFunction

 

   PublicSubNew()
      
Dim MyRow As DataRow
      
Dim arrKeyWords() AsString, strKW AsString

      
Me.AcceptsTab = True

      
''Load all the keywords and the colors to make them 
      
Words.Columns.Add("Word")
      Words.PrimaryKey =
New DataColumn() {Words.Columns(0)}
      Words.Columns.Add("Color")

      arrKeyWords =
NewString() {"select", "insert", "delete", _
         "truncate", "from", "where", "into", "inner", "update", _
         "outer", "on", "is", "declare", "set", "use", "values", "as", _
         "order", "by", "drop", "view", "go", "trigger", "cube", _
         "binary", "varbinary", "image", "char", "varchar", "text", _
         "datetime", "smalldatetime", "decimal", "numeric", "float", _
         "real", "bigint", "int", "smallint", "tinyint", "money", _
         "smallmoney", "bit", "cursor", "timestamp", "uniqueidentifier", _
         "sql_variant", "table", "nchar", "nvarchar", "ntext", "left", _
         "right", "like","and","all","in","null","join","not","or"}

      ForEach strKW In arrKeyWords
         MyRow = Words.NewRow()
         MyRow("Word") = strKW
         MyRow("Color") = Color.LightCoral.Name
         Words.Rows.Add(MyRow)
      
Next

   
EndSub

 

   PublicProperty CaseSensitive() AsBoolean
      
Get
         
Return _SyntaxHighlight_CaseSensitive
      
EndGet
      
Set(ByVal Value AsBoolean)
         _SyntaxHighlight_CaseSensitive = Value
      
EndSet
   EndProperty

 

 

EndClass   

 

Update July 8th, 2008: Here's a link that shows a couple tips that may help in writing your own Syntax Highlighting RichTextBox control:

http://codebetter.com/blogs/patricksmacchia/archive/2008/07/07/some-richtextbox-tricks.aspx


Viewing all articles
Browse latest Browse all 6

Trending Articles