Cognitive Mileage

Flicker-Free Syntax Highlighting: A Purely .NET Solution

Posted on: April 6, 2008

One of the number one problems for someone trying to implement syntax highlighting on a .NET platform is that when updating the RichTextBox to have the updated highlights, there is flickering. You have to highlight and change every keyword every time the user enters a new character (the TextChanged event).

There are two common methods. The first is to simply repaste all of the code into the RichTextBox and change the text formatting as you paste. The second is to highlight all the pieces of code and color or uncolor them as needed. Both cause undesirable flicker.

Stopping the RichTextBox Window Update without Win32
The flicker comes because the RichTextBox is updating every time you highlight a new word. The only solutions I’ve seen people offer to stop this is to DllImport Win32 libraries and do a LockWindowUpdate on the RichTextBox or send it a WM_SETREDRAW message.

Most people, upon discovering it and being given no alternative, find that solution disappointing. There should be a purely .NET solution, they say.

I’ve found one. I had to: I’m using IronPython Studio and, AFIAK, it can’t do DllImport.

The Solution
This is written in Python but can easily be translated to C# or VB.

def _rTextBox_TextChanged(self, sender, e):
    # Create new (invisible) RichTextBox for processing
    rt = RichTextBox()
    # Make sure the font is the same
    rt.Font = self._rTextBox.Font
    # But only paste unformatted Text
    # to erase formatting on non-keywords
    rt.Text = self._rTextBox.Text
    # Save cursor position
    user_pos = self._rTextBox.SelectionStart

    # Do text highlighting on invisible RichTextBox
    …

    # Now paste formatted text back into original (visible) RichTextBox
    self._rTextBox.Rtf = rt.Rtf
    # Reset cursor position
    self._rTextBox.SelectionStart = user_pos

The basic idea is that you create your own (invisible) RichTextBox within the code, copy the Text (unformatted text) from the visible RichTextBox into it, highlight the keywords, then paste the Rtf (formatted text) back into the visible RichTextBox. That way there is no flickering while you are doing the highlighting.

Drawbacks
There is still some minor flickering when the text gets large enough to consume more than a page. Also, the scroll bar position is reset when you edit text above the bottom line of the text.

Advertisements

13 Responses to "Flicker-Free Syntax Highlighting: A Purely .NET Solution"

If you need to access unmanaged code (win32 APIs etc) from IronPython, you can do it without using ‘DllImport’ with Dynamic Platform Invoke.

There is a partial implementation of ctypes for IronPython in the FePy project that shows how to do dynamic platform invoke – it’s very easy.

Thank you! Do you know how to do this in IronPython Studio? Importing ctypes isn’t working for me.

You will need to look at the code in the ctypes module and copy and paste the bits you need – wither that or see if you can add the ‘ctypes.py’ file to your IronPython Studio project.

In general I prefer to use a ‘real’ Python IDE (like Wing) and just use IronPython studio to generate code for Winforms or WPF.

Thank you for your continued help, Michael. Unfortunately, I have a dilemma. I cannot get IronPython Studio to import ctypes because it can’t import the dynamic library _ctypes. And I have no idea how to get Wing to create executable files.

I “updated” IronPython Studio to use Python 2.5 with the following two lines

import sys
sys.path.append(“C:\\Python25\\Lib”)

However, it isn’t a real update because, like I said, it can only import non-dynamic libraries.

The ctypes module I am talking about is ctypes from the FePy project – *not* from Python 2.5.

ctypes in FePy does dynamic platform invoke and tries to provide the same interface as the one in the Python standard library.

FePy is an IronPython distribution and can be found at: http://fepy.sf.net/

There is an example of using it at:

http://www.ironpython.info/index.php/Access_Unmanaged_Code_with_Dynamic_P/Invoke

Michael

Thank you again, Michael. Unfortunately, it does not appear that WDLL is a member of ctypes as shown in the example.

I don’t see any WDLL in the definition they list which, AFAIK, is equivalent to the one from FePy (I downloaded FePy and copied the contents of ctypes.py to IronPython Studio as you suggested). Any idea why WDLL isn’t there or what can be done?

I tried

usr = ctypes.pinvoke_dll(“user32.dll”)

but when I then call

usr.LockWindowUpdate(rTextBox)

it says “NoneType object is not callable” and points to this line in this block of code in ctypes.py:

def __getattr__(self, name):
if is_special_name(name):
raise AttributeError(name)
method = self.method_class(self.name, name)
setattr(self, name, method)
return method

Hmmm… you’re right. I’ve posted a message to the IronPython mailing list about this.

Okay. Thanks Michael.

Thank u very much, code is working fine.
I converted to vb.net here is the code::

Dim p As Integer
dim Richtextbox3 as new Richtextbox();

‘Setting the richtextbox3 boundary to existing richtextbox1 boundary

RichTextBox3.Width = RichTextBox1.Width
RichTextBox3.Height = RichTextBox1.Height

RichTextBox3.Font = RichTextBox1.Font
RichTextBox3.Text = RichTextBox1.Text

p = RichTextBox1.SelectionStart

‘Your keyword highlighter code

RichTextBox1.Rtf = RichTextBox3.Rtf
RichTextBox1.SelectionStart = p

Keyword Highlighter Code…..

‘Syntax function will perform keyword highlighting

‘call syntax function from richtextbox1 changed event

Private Sub RichTextBox1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles RichTextBox1.TextChanged

syntax()

End Sub

‘————————————–
‘syntax function

Function syntax()

Dim words As New List(Of String)
words.Add(“sandeep”); ‘keyword
words.Add(“kumar”); ‘keyword

Dim str As String
Dim p As Integer

RichTextBox3.Text = RichTextBox1.Text
p = RichTextBox1.SelectionStart

‘To keep track of the current line being processed

Dim lineNumber As Integer

‘To check if it as some text init
If RichTextBox3.Text.Length > 0 Then

‘Resetting richtextbox1 text to default

Dim selectStart As Integer = RichTextBox1.SelectionStart

RichTextBox3.Select(0, RichTextBox3.Text.Length)
RichTextBox3.SelectionColor = Color.Black
RichTextBox3.DeselectAll()

‘check each keyword in the RichTextBox3 text

For Each oneWord As String In words
Dim pos As Integer = 0

‘It wiil be greater/equal only if the keyword is found

Do While RichTextBox3.Text.ToUpper.IndexOf(oneWord.ToUpper, pos) >= 0

‘Assigning keyword index positon

pos = RichTextBox3.Text.ToUpper.IndexOf(oneWord.ToUpper, pos)

‘line number of the found keyword

lineNumber = RichTextBox3.GetLineFromCharIndex(pos)
str = RichTextBox3.Text

‘If it is not the first word in first line

If pos – 1 > 0 Then

‘keyword is the first word in that line

If (RichTextBox3.GetFirstCharIndexFromLine(lineNumber)) = pos Then

If ((RichTextBox3.GetFirstCharIndexFromLine(lineNumber) + RichTextBox3.Lines(lineNumber).Length)) > (pos + oneWord.Length) Then

If str(pos + oneWord.Length) = ” ” Or str(pos + oneWord.Length) = vbTab Then
RichTextBox3.Select(pos, oneWord.Length)
RichTextBox3.SelectionColor = Color.Blue

End If

‘only one word i.e keyword in that line
Else
RichTextBox3.Select(pos, oneWord.Length)
RichTextBox3.SelectionColor = Color.Blue
End If

‘To check lastword in that line is keyword or not
ElseIf ((RichTextBox3.GetFirstCharIndexFromLine(lineNumber) + RichTextBox3.Lines(lineNumber).Length)) = (pos + oneWord.Length) Then

‘to check if the previous charecter is space or tab

If str(pos – 1) = ” ” Or str(pos – 1) = vbTab Then
RichTextBox3.Select(pos, oneWord.Length)
RichTextBox3.SelectionColor = Color.Blue
End If

‘Keyword is not the first and last word
ElseIf ((RichTextBox3.TextLength – (pos + oneWord.Length)) > 0) Then

If (str(pos + oneWord.Length) = ” “) And (str(pos – 1) = ” “) Then
RichTextBox3.Select(pos, oneWord.Length)
RichTextBox3.SelectionColor = Color.Blue

ElseIf (str(pos + oneWord.Length) = ” “) And (str(pos – 1) = vbTab) Then
RichTextBox3.Select(pos, oneWord.Length)
RichTextBox3.SelectionColor = Color.Blue

ElseIf (str(pos + oneWord.Length) = vbTab) And (str(pos – 1) = vbTab) Then
RichTextBox3.Select(pos, oneWord.Length)
RichTextBox3.SelectionColor = Color.Blue

ElseIf (str(pos + oneWord.Length) = vbTab) And (str(pos – 1) = ” “) Then
RichTextBox3.Select(pos, oneWord.Length)
RichTextBox3.SelectionColor = Color.Blue

End If

End If

‘first word in the line
ElseIf pos = 0 Or (pos – 1) = 0 Then

‘only one word i.e keyword is the first word in first line

If ((RichTextBox3.TextLength – (pos + oneWord.Length)) = 0) Or (((RichTextBox3.Lines(lineNumber).Length) – (pos + oneWord.Length)) = 0) Then
RichTextBox3.Select(pos, oneWord.Length)
RichTextBox3.SelectionColor = Color.Blue

‘if keyword is not the first word

ElseIf RichTextBox3.TextLength – (pos + oneWord.Length) > 0 Then

If str(pos + oneWord.Length) = ” ” Or str(pos + oneWord.Length) = vbTab Then
RichTextBox3.Select(pos, oneWord.Length)
RichTextBox3.SelectionColor = Color.Blue
End If
End If
End If

pos += 1
Loop
Next

RichTextBox3.SelectionLength = 0
RichTextBox3.SelectionStart = selectStart
RichTextBox3.SelectionLength = 0
RichTextBox3.SelectionColor = Color.Black
End If

RichTextBox1.Rtf = RichTextBox3.Rtf
RichTextBox1.SelectionStart = p

‘———————————–
Return 0
End Function

‘—————————————–
This code is perfectly working , reply if any improvements has to be done.

anyone would like to write for http://www.ultimateprogrammingtutorials.blogspot.com ?

come and see write for us

Lawrence County Man Van London Facility. Matches and lighters are
tools, not toys. In many instances you think your home is to always have a deep sleep.
Royal Berkshire Fire Authority brought two charges following an inspection at the store in June 2010.

If you’re generating circuits breaking, call a professional even if and have him review the system and perhaps bring it up to code have been delayed by bureaucratic discretion and budget considerations. However, unlike lightning, arc flashes are so hazardous that OSHA regulations require all employers to conduct frequent arc flash analyses in the workplace. That is why fire safety training and emergency preparedness if possible. 13 Doors to hazardous areas that are shimmed open. Check your electrical wires and extension cords should not be allowed at all.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: