Click here to Skip to main content
Email Password   helpLost your password?

Sample Image - RichTextBoxHS.jpg

Introduction

We needed a control with background highlighting capabilities, so after looking everywhere, I ended up writing one. I found many people on the UseNet Groups and discussion threads asking for such a control and no one every answered. Well, here's an answer. It's kind of a kludge, but seems to work OK. It has NOT been through our QA cycle yet so use it at your own risk but I think it's pretty solid.

Apparently, there is an RTF tag called \highlight#. The RichTextBox control understands how to display the \highlight# tag, but the control does not provide any means of setting the tag. The reason I call my solution a kludge, is because the only way I could make it work is to scrape the raw RTF out of the control, manually parse it, strip out any existing \highlight# tags, rebuild the RTF color table, and manually insert the \highlight# tag myself. It seems to work ... but I'm not comfortable I know enough about RTF document structures to have thought of every scenario and every possible internal layout which can exist inside an RTF document. Bottom line, there may be RTF Documents which defeat my approach.

The RichTextBoxHS control is a subclass of the standard .NET RichTextBox. I've done several such controls which subclass one of the standard .NET controls and I always have a big problem getting the Visual Studio .NET Toolbox to recognize them. Bottom line ....

It takes "Funky" steps to recreate the RichTextBoxHS control

These steps (however funky) are required to recreate this control. I still haven�t deduced why, but unless you use Visual Studio�s tools to initially create the UserControl, the control never gets added to the ToolBox! So, for success, follow these steps:

Rather than repeating, step by step, how this approach works, I heavily commented the below code.

Imports System.Drawing
Imports System.Text
Public Class RichTextBoxHS
    Inherits Windows.Forms.RichTextBox

#Region " Windows Form Designer generated code "
    Public Sub New()
        MyBase.New()
        'This call is required by the Windows Form Designer.

        InitializeComponent()
        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.

    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer

    Private components As System.ComponentModel.IContainer
    'NOTE: The following procedure is required by the Windows Form Designer

    'It can be modified using the Windows Form Designer.  

    'Do not modify it using the code editor.

    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        components = New System.ComponentModel.Container()
    End Sub

#End Region


    Public WriteOnly Property SelectionBackColor() As Color
        Set(ByVal Value As Color)
            'First, test SelectedText property NOT SelectedRTF property because

            '...SelectedRTF will never be nothing, it will always have at least

            '...the current default Font table

            If Me.SelectedText Is Nothing Then Exit Property
            Dim sb As New StringBuilder()           'use StringBuilder for speed 

                                                    'and cleanliness

            Dim SelText As String = Me.SelectedRtf  'move to local string for speed

            Dim strTemp As String                   'used twice for ease of calculating 

                                                    'internal coordinates

            Dim FontTableEnds As Integer            'end character of the rtf font table

            Dim ColorTableBegins As Integer         'beginning of the rtf color table

            Dim ColorTableEnds As Integer           'end of the rtf color table

            Dim StartLooking As Integer             'used to walk a string appending chunks

            Dim HighlightBlockStart As Integer      'used to find "\highlight#" block for 

                                                    'stripping

            Dim HighlightBlockEnd As Integer        'used to find "\highlight#" block for 

                                                    'stripping

            Dim cycl As Integer                     'used in For/Next loops

            Dim NewColorIndex As Integer = 0        'new color table index for incoming color


            'find the end of the font table

            FontTableEnds = InStr(1, SelText, "}}")
            'add the header and font table to the string accumulator

            sb.Append(Mid(SelText, 1, FontTableEnds + 1))

            'find the color table start

            ColorTableBegins = InStr(FontTableEnds, SelText, "{\colortbl")
            If ColorTableBegins = 0 Then 'no color table exists 

                'add a color table header

                sb.Append("{\colortbl ;")
                'no color table so for later use make the ColorTableEnd the same 

                ' as FontTableEnds

                ColorTableEnds = FontTableEnds
                'default our new color table index to 1 since it will be the only one

                'remember Color table index 0 is reserved 

                NewColorIndex = 1
            Else 'a color table already exists

                'find the end of the color table

                ColorTableEnds = InStr(ColorTableBegins, SelText, "}")
                'backup one character so as to exclude the brace

                ColorTableEnds -= 1
                'need to count the quantity of semi;colons which will

                '... determine what color table index number our new color will be

                strTemp = Mid(SelText, FontTableEnds + 2, 
                              (ColorTableEnds - FontTableEnds) - 1)
                For cycl = 1 To strTemp.Length
                    If Mid(strTemp, cycl, 1) = ";" Then NewColorIndex += 1
                Next
                'append the color table without end brace

                sb.Append(strTemp)
            End If

            'append the color table entry for the highlight color

            sb.Append("\red" & Trim(Value.R.ToString))
            sb.Append("\green" & Trim(Value.G.ToString))
            sb.Append("\blue" & Trim(Value.B.ToString))
            'append the table entry terminator semi;colon


            sb.Append(";")
            'append the color table terminating brace

            sb.Append("}")
            'append the new highlight tag

            sb.Append("\highlight" & Trim(NewColorIndex.ToString))
            'Drop into a single string for easier manipulation

            strTemp = Mid(SelText, ColorTableEnds + 2, 
                          (SelText.Length - ColorTableEnds) - 1)

            'begin at first character

            StartLooking = 1
            'append everything remaining, but strip all remaining highlight tags

            Do
                'find a "\highlight" block

                HighlightBlockStart = InStr(StartLooking, strTemp, "\highlight")
                'if no more "\highlight" block found

                If HighlightBlockStart = 0 Then
                    'append everything remaining

                    sb.Append(Mid(strTemp, StartLooking, 
                                  strTemp.Length - StartLooking))
                    'we're done appending

                    Exit Do
                End If
                'calculate the end of the word "highlight"

                HighlightBlockEnd = HighlightBlockStart + 9
                'accomodate color tables with over 9 colors and thus multi-digit 

                'color indexes Plus, watch for (and discard) ONE space if it 

                'immediately follows the last digit

                Do
                    'keep stepping past end

                    HighlightBlockEnd += 1
                    'watch for (and discard) ONE space if it immediately follows the

                    ' last digit

                    If Mid(strTemp, HighlightBlockEnd + 1, 1) = " " Then
                        HighlightBlockEnd += 1
                        Exit Do
                    End If
                    'looking for the first non-numeric character

                Loop While InStr(1, "0123456789", Mid(strTemp, HighlightBlockEnd + 1, 1))
                'append this block

                sb.Append(Mid(strTemp, StartLooking, (HighlightBlockStart - StartLooking)))
                'move the start forward past the last "\highlight#" block

                StartLooking = HighlightBlockEnd + 1
            Loop

            Me.SelectedRtf = sb.ToString
        End Set
    End Property


    Public Sub FindHighlight(ByVal SearchText As String, ByVal HighlightColor As Color, _
                             ByVal MatchCase As Boolean, ByVal WholeWords As Boolean)
        Me.SuspendLayout()
        Dim StartLooking As Integer = 0
        Dim FoundAt As Integer
        Dim SearchLength As Integer
        Dim RTBfinds As RichTextBoxFinds
        If SearchText Is Nothing Then Exit Sub
        Select Case True
            Case MatchCase And WholeWords
                RTBfinds = RichTextBoxFinds.MatchCase Or RichTextBoxFinds.WholeWord
            Case MatchCase
                RTBfinds = RichTextBoxFinds.MatchCase
            Case WholeWords
                RTBfinds = RichTextBoxFinds.WholeWord
            Case Else
                RTBfinds = RichTextBoxFinds.None
        End Select
        SearchLength = SearchText.Length
        Do
            FoundAt = Me.Find(SearchText, StartLooking, RTBfinds)
            If FoundAt > -1 Then Me.SelectionBackColor = HighlightColor
            StartLooking = StartLooking + SearchLength
        Loop While FoundAt > -1
        Me.ResumeLayout()
    End Sub

    Public Sub BackColorSetWhole(ByVal BackColorDefault As Color)
        Me.SelectAll()
        Me.SelectionBackColor = BackColorDefault
    End Sub

End Class

BUGS ....

If anyone finds bugs, or discovers an RTF Document which defeats my approach, please let me know. I will try to fix any problems.

Enjoy,

Frederick Volking
Senior Architect
Hunter Stone, Inc
http:HunterStone.Com

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
General2 Questions
Jared James Sullivan
18:32 18 Jan '09  
1. When I call HighlightColor routine the RTF box always scrolls to the selected keyword..this slows thing down considerably. I can actually see the selection of the keyword while it is being colored. Is there any reason why .SuspendLayout might not work on Vista?

2. I am also suffering from 'mutilation' of color table when I manually set the RTF property. When I say mutilation, I mean the color become all mixed up, what was CF3 becomes CF1. Sometimes they match up most times they dont.

As you can see I am almost jaded into not using color syntaxing by these 2 bugs. Any help would be appreciated.
QuestionI can't change color text that I selected
Member 3100142
21:35 28 Feb '08  
I have some problem with RichTextBox in VB.NET.
I can't change color text that I selected.
when read from file I want to see the text that I applied with the color.

I'm waiting for reply
Thanks,

modified on Friday, February 29, 2008 4:55 AM

Generalcannot use RichTextBoxHS in application
pallavipatil01
3:33 14 Jun '06  
i'm tring to use ur control RichTextBoxHS. but i'm unable to drag it on form.
Plzz tell me sir how to use it in application.

pallavi
GeneralFantastic example!
DbMan17
11:35 4 May '06  
Just implemented this into my application and it worked perfectly! Just wanted to say thanks for the great example! Your effort is much appreciated!

W. Scott Morgan
Perfect Design Software
GeneralSelectionBackColor is in .NET Framework version 2.0.
ErichG
6:22 14 Feb '06  
Microsoft has added this property to the Framework now - no need to add special code any longer
GeneralNeed the code in C#
spvarapu
23:27 9 Mar '05  
It is very good application. I need this to be in c#. Can any body help...
thanks in advance

Bye
srinu

Sreenivasulu Palavarapu
Lera Technologies,
Secunderabad.
GeneralRe: Need the code in C#
ttgiang
8:02 12 Sep '05  
http://www.ischool.washington.edu/groove/solutions/hightlight_rtb.html
Generalclass possibility
Pyro Joe
17:55 25 Feb '05  
I don't know a lot about c# as of yet, but if you were to put all your code for highlighting into a single class, I could access that for multiple applications rather than rewriting the code. Assuming I'm right about that being how classes work, you should make one, because that would be a very helpful function.
GeneralRe: class possibility
Pyro Joe
17:57 25 Feb '05  
whoops. I almost didn't realize I was reading a visual basic project. nv/m
GeneralOdd "newline"
Opryshok
23:47 5 Jul '04  
Clear RTB.Text. Enter into RTB text i.e. "hello". Go to first postion, Press [SHIFT]+[End] (select all the first line). Press button to highlight with yellow. "Newline" appears after "hello" in RTB.
GeneralIf no selection then BUG?
Jon Jake
6:21 29 Jan '04  
First of all thanks! Used it and... learned from it. Added only the following line:

If FontTableEnds < 1 Then Exit Property

As if FontTableEnds = 0 throws an exception. Was this the intention?
GeneralWhy so complicated?
Martin Mueller
21:29 30 Jul '02  
I appreciate your efforts, but I think setting the background color for areas in a richtext control could be done a lot easier.
There's a message EM_SETCHARFORMAT with which you can set display properties for parts of your richedit control.

For RichEdit V2 and up you can use the struct CHARFORMAT2 to specify the properties including background color (flag CFM_BACKCOLOR and struct member crBackColor). For a description take a look at ms-help://MS.VSCC/MS.MSDNVS/winui/richedit_73si.htm
I've published an extension for RichTextBox on CodeGuru, which you could easily modify to add the ability to set the background color - interop and struct definitions are already included...
Take a look:
http://www.codeguru.com/cs_controls/RichTextEx.html
mav
GeneralBecause I didn't know no'better!
volking
7:11 31 Jul '02  
Those of you who hark from a C++ past have many advantages over us poor VB coders. Thing like CallBacks, Messages, and such are still mysteries to most of us. (smile) VB Coders are the ultimate "Tool-Users" where C++ coders are the defacto "Tool Makers". When a VB Coder needs a tool that does a certain thing, and can't find one, he does his best to build one ... which is what I did. Alas, my solution is a "Tool User's" solution and your solution is a "Tool Builder's" solution.

Now that I know an "elegant" solution does exists, I will do my best to implement the "elegant" solution!

Thanks for the feed-back!



Frederick Volking

GeneralRe: Because I didn't know no'better!
Martin Müller
10:33 2 Aug '02  
Sorry, I didn't mean to sound like "mr. smart ass" Blush

Apart from that, it's quite fascinating what you can do using plain windows messages. And, although it is not really good object oriented programming style, basic windows messages are what literally everything boils down to. So if you're looking for a certain function a control doesn't have (but you have seen this feature at work somewhere) then chances are there's a windows message the control understands which does exactly what you want.

Martin Müller ( Cool )
GeneralRe: Because I didn't know no'better!
volking
14:27 2 Aug '02  
Martin - You did NOT sound like "mr. smart ...." I've been playing with computers and programming for almost three decades. I learned early that some of the most profound discoveries come from taking a risk and explainging something the way "I" see it. It's prople like you, willing to show me a "better-way" that often result in such profound discoveries!

DO NOT STOP! Big Grin I need the insights!

Frederick Wink

Frederick Volking
HunterStone, Inc.
fvolking@hunterstone.com
803.748.1108
GeneralRe: Because I didn't know no'better!
FredAdams
6:47 26 Feb '04  
I have been working on creating something exactly like: What looks like the screen-shot you have posted here. When I was working on the project, I found that there is so little support for such a promising object. It felt like that I was working in the total darkness.
I have not downloaded your code yet, but I will definitely try it when I have the time and a chance, next.
Thank you Frederick for saving us valuable time and agony by giving us something that takes so long to create (Not to mention constantly throwing dart in the total darkness when working on a project like this one!)
You effort is greatly appreciated!!!
fred
GeneralCarret in RichTextBox
Step
21:46 29 Jul '02  
Is there a possibility to hide the carret in RichTextBox ?Confused
GeneralRe: Carret in RichTextBox
Juvenile
5:23 11 Jan '04  
Public Declare Function HideCaret Lib "user32" Alias "HideCaret" (ByVal hwnd As Integer) As Integer

'Fucntion Call

HideCaret(RTB.Handle.ToInt32)



Juvenile


Last Updated 30 Jul 2002 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010