1. Computing & Technology

Discuss in my forum

RichTextBox - Selecting, Deleting, and Moving Lines

RichTextBox is more than just a TextBox with more properties and methods

By , About.com Guide

Updated January 10, 2012

Dr. Peter Zilahy Ingerman, a frequent contributor to these pages, asked a question that turned out to be so interesting that it deserved more than just a reply. It deserved this article. Peter asked:

I have programmed a function that adds lines to a RichTextBox. I use this code to add lines:


RichTextBox.AppendText(myTextString & vbCrLf)

This much works just as I want it to.

I need to write the code that will delete the top line of the RichTextBox. I attempted to use the following code:


I = InStr(rtbStory.Text, vbCrLf) - 1
If I >= 0 Then rtbStory.Text = _
   RichTextBox.Text.Substring(I + Len(vbCrLf))

The problem is that InStr consistantly returns zero, saying that there aren't any "vbCrLf" strings.

Clearly I am not understanding some elementary property of a RichTextBox ... and, equally clearly, Microsoft Help isn't helping for sour owl jowls.

Right you are, Peter! The problem is that "Rich Text" is to "Text" as "differential and integral calculus" is to "arithmetic". And right you are again because your code works quite well with a regular text box. I coded up a little more complete example to prove it.


Dim C As Char = "A"
Private Sub txtAddLine_Click( ... 
   Dim T As New String(C, 5)
   txtText.AppendText(T & vbCrLf)
   C = Chr(Asc(C) + 1).ToString
End Sub

Private Sub txtDelLine_Click( ...
   Dim I As Int16 = 0
   I = InStr(txtText.Text, vbCrLf) - 1
   If I >= 0 Then txtText.Text =
      txtText.Text.Substring(I + Len(vbCrLf))
End Sub

The illustration below shows a regular TextBox after five lines were added and two deleted.

--------
Click Here to display the illustration
--------

But when the same code is used to add text to a RichTextBox, it doesn't work for exactly the reason Peter noted. If you examine the Text property of the RichTextBox, it just gets more confusing. The Text property just shows the actual characters in the RichTextBox. (But when you're counting characters with the RichTextBox Index property, there is an extra character per line that you have to include.)

The reason is that the RichTextBox component converts what is really there into ASCII text and leaves out a lot, including the line break characters that Peter's code inserted. In fact, the line break characters were converted to rich text and don't actually exist in the text. That's why the If statement in Peter's code failed. What is really there can be displayed with the Rtf property:

--------
Click Here to display the illustration
--------

Rich text can be used for highly formatted text and includes things like the font, the document margins, even pictures and other objects. For complete details, search MSDN for "Rich Text Format (RTF) Specification". (When I was in corporate data processing, I always recommended RTF as an editable document interchange format. Microsoft really did a great sales job in convincing the world to use Word instead of the free and more convertable WordPad which uses RTF!)

It's quite possible to do something similar to Peter's code with a RichTextBox component, but you have to use the methods and properties of rich text to do it. There might be better ways (Let me know if you find one!), but this seems to work. (The sender and e parameters are not shown for simplicity. More complete code has been included at the end of the article.)


Dim C As Char = "A"
Private Sub rtbAddLine_Click( ...
   Dim T As New String(C, 5)
   rtbText.AppendText(T & vbCrLf)
   C = Chr(Asc(C) + 1).ToString
End Sub

Private Sub rtbDelLine_Click( ...
   Dim I As Int16
   Do While rtbText.GetLineFromCharIndex(I) < 1
      I += 1
   Loop
   rtbText.Select(0, I)
   rtbText.Cut()
End Sub

(The Do loop crashes when there is no text in the component. It probably should be enclosed in a Try-Catch block.)

The GetLineFromCharIndex returns the line number of the line that the character that is indexed is in. So the second line can be found by simply incrementing until the next line is returned. After that, those characters are selected and then cut out of the document, just like you might do in Word!

A few years after this was written, Charles read the article and asked if I had something that showed how to parse all of the RichTextBox lines, rather than just deleting the top line as Peter wanted.

I do now, Charles.

To do this, you have to get a little trickier counting indexes. Fortunately, RichTextBox also has a method called GetLineFromCharIndex that will tell me which line the mouse pointer is on. Here's code that will cut a line from the top RichTextBox and paste it into a ListBox.


Private Sub btnDelSelected_Click( ...
    Dim I As Int16 =
        rtbText.GetFirstCharIndexOfCurrentLine
    Dim LineNumber As Integer
    LineNumber =
        rtbText.GetLineFromCharIndex(
            rtbText.GetFirstCharIndexOfCurrentLine)
    Do While _
        rtbText.GetLineFromCharIndex(I) < LineNumber + 1
        I += 1
    Loop
    rtbText.Select(
        rtbText.GetFirstCharIndexOfCurrentLine,
        rtbText.Lines(LineNumber).Length)
    rtbText.Cut()
    lbxParsedLines.Items.Add(Clipboard.GetText)
End Sub

In the code for Peter, I never had to worry about the length of the line because I just started at the beginning and found the end of the first line. In this code, I do, because individual lines can have different lengths. So the variable I has to be initialized with the index number of the first character of whatever line the mouse pointer is in. For similar reasons, I have to get a line number where the mouse pointer is and use that in the Do loop instead of just the number 1. Then it's a simple matter of cutting the text (Which is placed in the Clipboard for me by .NET.) and adding it to the ListBox.

Here's the result of this new program.

--------
Click Here to display the illustration
--------

Note that the line itself is not actually selected and deleted from the RichTextBox so "blank lines" remain. This is not the vbCrLf that Peter was looking for, but it is represented by an index position in the line (so it has to be counted) and performs much the same way.

©2012 About.com. All rights reserved.

A part of The New York Times Company.