Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1301
  • Last Modified:

How can I show whitespace; e.g. tabs, spaces, in a richtextbox control

I have simple text file viewer written in VB.NET in which I need a feature to show whitespace characters.  I have seen this option effectively in editors such as EditPlus, SuperEdi, etc.  I can't seem to find any VB.NET or C# source code which illustrates showing whitespace or special characters (selectable option.)  I have figured out how to catch space characters and translate them to bullet chars and even change the color of the fly, too, but the tab handling has me stumpped.  I can replace the tab (chr(9)) with a different character and pad with spaces within the KeyPress event, but I can't figured out how to maintain the tab positioning and navigation (arrow keys) appropriately.  Here are the rules:

1. Working code can be in VB.NET or C#.
2. Must be able to replace tabs on the fly (user is typing) whilst maintaining tab positioning especially when the caret is moved within the control (using arrows keys, etc.)
3. Replacement character and padding must take the same amout of space as the tab chracter would:
<tab> below means actual tab (chr(9) a.k.a. \t or vbTab)
Example:  Original text: testing<tab>this
               Desired text: testing>>     this

Thanks,

Matt
0
mesterak
Asked:
mesterak
  • 7
  • 4
1 Solution
 
arif_eqbalCommented:
Hi mesterak
So is it that you just want to handle the Arrow Keys ???

Say whenever user presses TAB I replace it with some special character + a few spaces
And when he uses Arrow keys for navigation I handle that also for eg.

He says:    testing<tab>this
I Display:   testing>>     this

Now if his cursor is at position 'g' and he presses Right Arrow Key
I move him to the position 't' (i.e. past the spaces)
and vice versa for Left Arrow Key...

BUT... what if he uses Mouse button and staright away clicks in between the space between the '>>' and the 't'

What if he uses DELETE key, I hope you'd like to handle all the cases or is it just the Arrows???

Now you have said ---> padding must take the same amout of space as the tab chracter
So if the Tab was taking 5 spaces now we will have Two '>>' and Three white space.

Can this do as well, I keep the Tab as it is + the special Char '>>'. I mean when he presses TAB I replace it with Special Char + TAB, rahter than Special Char + Spaces. This will simplify a lot of things
For eg. user will not be able to click in between the white space (as there won't be any) etc. etc.


0
 
arif_eqbalCommented:
OK
Here's a sample code....
I am using Spaces with a Tilde character (~)
so whenever on types TAB we get "~    " instead (~ and 4 spaces, this you can modify to suite your need)
I have tried to handle Arrow Keys, BackSpace, Delete and when a uses Mouse instead of Arrow keys to move.

here goes....


    Private Const TabSpace As Integer = 5 'No of Space a Tab represents

    Private Sub RichTextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles RichTextBox1.KeyPress
        If e.KeyChar = Chr(Keys.Tab) Then
            RichTextBox1.SelectedText = "~" & Space(TabSpace - 1)
            e.Handled = True
        End If
    End Sub

    Private Sub RichTextBox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles RichTextBox1.KeyDown
        If e.KeyCode = Keys.Right Then
            Try
                If (RichTextBox1.Text.Substring(RichTextBox1.SelectionStart, 1) = "~" Or RichTextBox1.Text.Substring(RichTextBox1.SelectionStart, 1) = " ") And RichTextBox1.Text.Substring(RichTextBox1.SelectionStart + 1, 1) = " " Then
                    SendKeys.Send("{RIGHT}")
                End If
            Catch ex As ArgumentOutOfRangeException
            End Try
        ElseIf e.KeyCode = Keys.Left Then
            Try
                If RichTextBox1.Text.Substring(RichTextBox1.SelectionStart - 1, 1) = " " And (RichTextBox1.Text.Substring(RichTextBox1.SelectionStart - 2, 1) = " " Or RichTextBox1.Text.Substring(RichTextBox1.SelectionStart - 2, 1) = "~") Then
                    SendKeys.Send("{LEFT}")
                End If
            Catch ex As ArgumentOutOfRangeException
            End Try
        ElseIf e.KeyCode = Keys.Delete Then
            Try
                If (RichTextBox1.Text.Substring(RichTextBox1.SelectionStart, 1) = "~" Or RichTextBox1.Text.Substring(RichTextBox1.SelectionStart, 1) = " ") And RichTextBox1.Text.Substring(RichTextBox1.SelectionStart + 1, 1) = " " Then
                    SendKeys.Send("{DEL}")
                End If
            Catch ex As ArgumentOutOfRangeException
            End Try
        ElseIf e.KeyCode = Keys.Back Then
            Try
                If RichTextBox1.Text.Substring(RichTextBox1.SelectionStart - 1, 1) = " " And (RichTextBox1.Text.Substring(RichTextBox1.SelectionStart - 2, 1) = " " Or RichTextBox1.Text.Substring(RichTextBox1.SelectionStart - 2, 1) = "~") Then
                    SendKeys.Send("{BKSP}")
                End If
            Catch ex As ArgumentOutOfRangeException
            End Try
        End If
    End Sub

    Private Sub RichTextBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles RichTextBox1.MouseUp
        Dim Index As Integer
        Index = Me.RichTextBox1.GetCharIndexFromPosition(New Point(e.X, e.Y))
        If Index > 0 And Index < RichTextBox1.TextLength Then
            SendKeys.SendWait("{LEFT}")
            SendKeys.Send("{RIGHT}")
        End If
    End Sub


0
 
mesterakAuthor Commented:
This solution is very close to achieving the except the ability to highlight text does not work and true tab position and following spaces after the ~ do not match up with the replaced tab and spaces that follow if the feature was turned-off.  I can live with the space mismatch and award you all of the points if you can rectify the text highlighting capability in your example.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
arif_eqbalCommented:
I warned you earlier its not going to be easy encapsulating all the features, but anyway we can try.

First problem, No. of spaces do not match the Tab Space, you can change the no. of spaces by setting the value of the variable "TabSpace" so that it matches exactly the space taken by Tab.

As for the second and third problem (Turn On/Off the feature and Highlight). I'll try to see if I can come up with something.

0
 
mesterakAuthor Commented:
Yes, you did warn me...you were right :)

I think have fixed the arrow movement problems.  I have also replaced using sendkeys everywhere except for in the MouseUp event (works great in there.)  The ONLY problem left appears to be in handling highlighting text by either using the mouse or via shift key + arrow key combinations; e.g. SHIFT+LEFT ARROW, SHIFT+RIGHT ARROW, etc.

Below is our code to work with.  You'll notice that I have implemented text coloring, etc. to spice up usability.  Please do your coding magic to fix the text highlighting!  I believe we'll be the first that I know of in open source to implement whitespace viewing cleanly in a VB.NET richtextbox control :)

Imports System.Text
Imports System.Text.RegularExpressions

Public Class Form1
    Inherits System.Windows.Forms.Form

#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.
    Friend WithEvents RichTextBox1 As System.Windows.Forms.RichTextBox
    Friend WithEvents CheckBox1 As System.Windows.Forms.CheckBox
    Friend WithEvents StatusBar1 As System.Windows.Forms.StatusBar
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.RichTextBox1 = New System.Windows.Forms.RichTextBox
        Me.CheckBox1 = New System.Windows.Forms.CheckBox
        Me.StatusBar1 = New System.Windows.Forms.StatusBar
        Me.SuspendLayout()
        '
        'RichTextBox1
        '
        Me.RichTextBox1.AcceptsTab = True
        Me.RichTextBox1.BackColor = System.Drawing.Color.White
        Me.RichTextBox1.Font = New System.Drawing.Font("Courier New", 9.75!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Me.RichTextBox1.ForeColor = System.Drawing.Color.MediumBlue
        Me.RichTextBox1.Location = New System.Drawing.Point(24, 40)
        Me.RichTextBox1.Name = "RichTextBox1"
        Me.RichTextBox1.Size = New System.Drawing.Size(368, 160)
        Me.RichTextBox1.TabIndex = 0
        Me.RichTextBox1.Text = ""
        '
        'CheckBox1
        '
        Me.CheckBox1.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Me.CheckBox1.Location = New System.Drawing.Point(24, 8)
        Me.CheckBox1.Name = "CheckBox1"
        Me.CheckBox1.Size = New System.Drawing.Size(168, 24)
        Me.CheckBox1.TabIndex = 1
        Me.CheckBox1.Text = "View typed spaces"
        '
        'StatusBar1
        '
        Me.StatusBar1.Location = New System.Drawing.Point(0, 285)
        Me.StatusBar1.Name = "StatusBar1"
        Me.StatusBar1.Size = New System.Drawing.Size(416, 16)
        Me.StatusBar1.TabIndex = 2
        Me.StatusBar1.Text = "StatusBar1"
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(416, 301)
        Me.Controls.Add(Me.StatusBar1)
        Me.Controls.Add(Me.CheckBox1)
        Me.Controls.Add(Me.RichTextBox1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private blnReplaceSpaces As Boolean = False
    Private TrackCaret As Integer = 0
    Private Const TabSpace As Integer = 5

    Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged
        RichTextBox1.Focus()
        TrackCaret = RichTextBox1.SelectionStart

        If CheckBox1.CheckState = CheckState.Checked Then
            blnReplaceSpaces = True

            If RichTextBox1.Text.Length > 0 Then
                Dim tmpString As String = RichTextBox1.Text
                tmpString = tmpString.Replace(Chr(32), Chr(149))
                tmpstring = tmpstring.Replace(Chr(9), Chr(187) + Space(TabSpace - 1))
                RichTextBox1.Text = tmpstring

                Dim Index As Integer = 0

                While Index < RichTextBox1.Text.Length

                    If RichTextBox1.Text.Substring(Index, 1) = Chr(149) Or RichTextBox1.Text.Substring(Index, 1) = Chr(187) Then
                        RichTextBox1.SelectionStart = Index
                        RichTextBox1.SelectionLength = 1
                        RichTextBox1.SelectionColor = Color.Peru
                    End If

                    Index += 1
                End While

                RichTextBox1.SelectionStart = TrackCaret
                RichTextBox1.Select(TrackCaret, 0)
                RichTextBox1.Focus()
            End If

        Else
            blnReplaceSpaces = False

            If RichTextBox1.Text.Length > 0 Then
                Dim tmpString As String = RichTextBox1.Text
                tmpString = tmpstring.Replace(Chr(187) + Space(TabSpace - 1), Chr(9))
                tmpString = tmpString.Replace(Chr(149), Chr(32))
                RichTextBox1.Text = tmpstring
                RichTextBox1.SelectAll()
                RichTextBox1.SelectionColor = Color.MediumBlue
                RichTextBox1.SelectionStart = TrackCaret
                RichTextBox1.Select(TrackCaret, 0)
                RichTextBox1.Focus()
            End If

        End If

    End Sub

    Private Sub RichTextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles RichTextBox1.KeyPress

        If e.KeyChar = Chr(32) And blnReplaceSpaces = True Then
            e.Handled = True
            RichTextBox1.SelectedText = Chr(149)
            TrackCaret = RichTextBox1.SelectionStart
            RichTextBox1.SelectionStart = TrackCaret - 1
            RichTextBox1.SelectionLength = 1
            RichTextBox1.SelectionColor = Color.Peru
            RichTextBox1.Select(TrackCaret, 0)
            RichTextBox1.SelectionColor = Color.MediumBlue
        ElseIf e.KeyChar = Chr(9) And blnReplaceSpaces = True Then
            e.Handled = True
            RichTextBox1.SelectedText = Chr(187) + Space(TabSpace - 1)
            TrackCaret = RichTextBox1.SelectionStart
            RichTextBox1.SelectionStart = TrackCaret - TabSpace
            RichTextBox1.SelectionLength = 1
            RichTextBox1.SelectionColor = Color.Peru
            RichTextBox1.Select(TrackCaret, 0)
            RichTextBox1.SelectionColor = Color.MediumBlue
        ElseIf e.KeyChar = Chr(9) And blnReplaceSpaces = False Then
            e.Handled = True
            RichTextBox1.SelectedText = Chr(9)
            TrackCaret = RichTextBox1.SelectionStart
            RichTextBox1.SelectionStart = TrackCaret - 1
            RichTextBox1.SelectionLength = 1
            RichTextBox1.Select(TrackCaret, 0)
        ElseIf Not e.KeyChar = Chr(149) And Not e.KeyChar = Chr(187) And Not e.KeyChar = Chr(8) And Not e.KeyChar = vbCr Then
            e.Handled = True
            RichTextBox1.SelectedText = e.KeyChar
            TrackCaret = RichTextBox1.SelectionStart
            RichTextBox1.SelectionStart = TrackCaret - 1
            RichTextBox1.SelectionLength = 1
            RichTextBox1.SelectionColor = Color.MediumBlue
            RichTextBox1.Select(TrackCaret, 0)
            RichTextBox1.SelectionColor = Color.MediumBlue
        End If

    End Sub

    Private Sub RichTextBox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles RichTextBox1.KeyDown

        If blnReplaceSpaces = True Then
            TrackCaret = RichTextBox1.SelectionStart
            Dim blnSelectedText As Boolean = False

            If RichTextBox1.SelectedText.Length > 0 Then blnSelectedText = True

            If e.KeyCode = Keys.Right Then
                Dim intLength = RichTextBox1.Text.Length

                If RichTextBox1.SelectionStart >= 0 And RichTextBox1.SelectionStart < intLength Then
                    Dim intTrackPos = RichTextBox1.SelectionStart

                    If Not blnSelectedText Then

                        While intTrackPos < intLength

                            If RichTextBox1.Text.Substring(intTrackPos, 1) = Chr(187) Then
                                e.Handled = True
                                RichTextBox1.SelectionStart = intTrackPos + TabSpace - 1
                                TrackCaret = RichTextBox1.SelectionStart
                                RichTextBox1.Select(TrackCaret, 0)
                            Else
                                e.Handled = False
                                RichTextBox1.Select(TrackCaret, 0)
                                Exit While
                            End If

                            intTrackPos += 1
                        End While

                    End If

                End If

            ElseIf e.KeyCode = Keys.Left Then

                If RichTextBox1.SelectionStart > 0 Then
                    Dim intTrackPos = RichTextBox1.SelectionStart - 1

                    If Not blnSelectedText Then

                        While intTrackPos >= 0

                            If RichTextBox1.Text.Substring(intTrackPos, 1) = " " Then
                                e.Handled = True
                                RichTextBox1.SelectionStart = intTrackPos
                                TrackCaret = RichTextBox1.SelectionStart
                                RichTextBox1.Select(TrackCaret, 0)
                            Else
                                e.Handled = False
                                RichTextBox1.Select(TrackCaret, 0)
                                Exit While
                            End If

                            intTrackPos -= 1
                        End While

                    End If

                End If

            ElseIf e.KeyCode = Keys.Delete Then

                Try

                    If Not TrackCaret = RichTextBox1.Text.Length Then

                        If RichTextBox1.Text.Substring(RichTextBox1.SelectionStart, 1) = Chr(187) Then
                            e.Handled = True
                            RichTextBox1.Text = RichTextBox1.Text.Remove(TrackCaret, 5)
                            RichTextBox1.Select(TrackCaret, 0)
                            ColorizeText()
                        Else
                            e.Handled = False
                        End If

                    Else
                        e.Handled = False
                    End If


                Catch ex As ArgumentOutOfRangeException
                    MsgBox("Key delete: " + ex.Message)
                End Try

            ElseIf e.KeyCode = Keys.Back Then

                Try

                    If RichTextBox1.SelectionStart > 0 Then
                        TrackCaret = RichTextBox1.SelectionStart - 1
                        Dim intOrigPos As Integer = TrackCaret
                        Dim blnStop As Boolean = False

                        If RichTextBox1.Text.Substring(TrackCaret, 1) = " " Then
                            e.Handled = True
                            TrackCaret = RichTextBox1.SelectionStart - 5
                            RichTextBox1.Text = RichTextBox1.Text.Remove(TrackCaret, 5)
                            RichTextBox1.Select(intOrigPos - 4, 0)
                            ColorizeText()
                        Else
                            e.Handled = False
                        End If

                    Else
                        e.Handled = False
                    End If

                Catch ex As ArgumentOutOfRangeException
                    MsgBox("Key back: " + ex.Message)
                End Try

            End If

        End If

    End Sub

    Private Sub RichTextBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles RichTextBox1.MouseUp

        If blnReplaceSpaces = True Then
            Dim Index As Integer
            Index = Me.RichTextBox1.GetCharIndexFromPosition(New Point(e.X, e.Y))

            If Index > 0 And Index < RichTextBox1.TextLength And RichTextBox1.SelectedText.Length = 0 Then
                SendKeys.SendWait("{LEFT}")
                SendKeys.Send("{RIGHT}")
            End If

        End If

    End Sub

    Sub CaretMoved(ByVal sender As Object, ByVal e As EventArgs)
        Dim SLen As Integer = 0
        Dim G As System.Drawing.Graphics = RichTextBox1.CreateGraphics
        Dim Rows As Integer = RichTextBox1.GetLineFromCharIndex(RichTextBox1.SelectionStart)
        Dim Cols As Integer = RichTextBox1.SelectionStart
        Dim I As Integer = 0
        While I < RichTextBox1.Lines.GetLength(0)
            SLen += RichTextBox1.Lines(I).Length + 1
            If SLen > Cols Then
                ' break
            End If
            System.Math.Min(System.Threading.Interlocked.Increment(I), I - 1)
        End While
        If (I = RichTextBox1.Lines.GetLength(0) - 1) AndAlso (RichTextBox1.Lines(I) = "") Then
            Cols = 0
        Else
            Dim P As Point = RichTextBox1.GetPositionFromCharIndex(Cols)
            Cols -= RichTextBox1.GetCharIndexFromPosition(New Point(0, P.Y))
        End If
        StatusBar1.Text = "Col: " + (Cols + 1).ToString
        StatusBar1.Text = StatusBar1.Text + " Row: " + (Rows + 1).ToString
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        AddHandler RichTextBox1.SelectionChanged, AddressOf CaretMoved
    End Sub

    Private Sub ColorizeText()
        Dim Index As Integer = 0
        TrackCaret = RichTextBox1.SelectionStart

        While Index < RichTextBox1.Text.Length

            If RichTextBox1.Text.Substring(Index, 1) = Chr(149) Or RichTextBox1.Text.Substring(Index, 1) = Chr(187) Then
                RichTextBox1.SelectionStart = Index
                RichTextBox1.SelectionLength = 1
                RichTextBox1.SelectionColor = Color.Peru
            End If

            Index += 1
        End While

        RichTextBox1.Select(TrackCaret, 0)
    End Sub

End Class
0
 
arif_eqbalCommented:
Hi

I just checked it highlighting is the problem due to the code in the MouseUP event
I have modified the MouseUp code, its still not perfect but acceptably good (hopefully)

so try replacing the earlier MouseUp event code with this one and see.

 Private Sub RichTextBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles RichTextBox1.MouseUp
        Dim Index As Integer
        Index = Me.RichTextBox1.GetCharIndexFromPosition(New Point(e.X, e.Y))
          Try
            If (RichTextBox1.Text.Substring(Index, 1) = "~" Or RichTextBox1.Text.Substring(Index, 1) = " ") And RichTextBox1.Text.Substring(Index + 1, 1) = " " Then
                SendKeys.SendWait("{LEFT}")
                SendKeys.Send("{RIGHT}")
            End If
        Catch ex As ArgumentOutOfRangeException
        End Try
    End Sub



Also to Toggle the feature On/OF try this out on a button click

    Private Sub CmdOnOff_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CmdOnOff.Click
        If CmdOnOff.Text = "ON" Then
            RichTextBox1.Text = RichTextBox1.Text.Replace(vbTab, "~" & Space(TabSpace - 1))
            CmdOnOff.Text = "OFF"
        Else
            RichTextBox1.Text = RichTextBox1.Text.Replace("~" & Space(TabSpace - 1), vbTab)
            CmdOnOff.Text = "ON"
        End If
    End Sub




0
 
arif_eqbalCommented:
Hi mesterak
Ignore my last comment....

your code is working fine, no need to replace the MouseUp event.

Now it seems the only issue is SHIFT+ARROW selection is it ???

I'll try to fix that....


0
 
arif_eqbalCommented:
OK here's your KeyDown event code...

I have modified your code to Add some more lines for handling Shift+Arrow (I have added Comments to show where the additional code starts and ends)

It is working fine with Shift+Right Arrow Key, But not with Shift+Left Arrow key.
The problem is with Left Arrow key we select in the reverse direction (Right to Left) now the Select method of the richTextBox selects only in the forward direction (Left to Right)

So I am not able to manually select the entire set of characters. I remember we used to have a method called "span" which allowed selection in backward direction but I could not find the method here. (But I sure remember having span method in RichTextBox control back in VB6 days)

Anyway so this code just requires one more thing a line of code to select in backward direction. I'll try to find a way for that and post you back. Meanwhile here's the code....

    Private Sub RichTextBox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles RichTextBox1.KeyDown

        If blnReplaceSpaces = True Then
            TrackCaret = RichTextBox1.SelectionStart
            Dim blnSelectedText As Boolean = False

            If RichTextBox1.SelectedText.Length > 0 Then blnSelectedText = True

            If e.KeyCode = Keys.Right Then
                Dim intLength = RichTextBox1.Text.Length

                If RichTextBox1.SelectionStart >= 0 And RichTextBox1.SelectionStart < intLength Then
                    Dim intTrackPos = RichTextBox1.SelectionStart

                    '---> Added Code Starts
                    If blnSelectedText Or RichTextBox1.Text.Substring(RichTextBox1.SelectionStart, 1) = Chr(187) Then
                        If (RichTextBox1.SelectionStart + RichTextBox1.SelectionLength) < RichTextBox1.TextLength Then
                            If e.Shift = True And RichTextBox1.Text.Substring(RichTextBox1.SelectionStart + RichTextBox1.SelectionLength, 1) = Chr(187) Then
                                RichTextBox1.Select(RichTextBox1.SelectionStart, RichTextBox1.SelectionLength + TabSpace - 1)
                            End If
                        End If
                        Exit Sub
                    End If
                    '---> Added Code Ends

                    If Not blnSelectedText Then

                        While intTrackPos < intLength

                            If RichTextBox1.Text.Substring(intTrackPos, 1) = Chr(187) Then
                                e.Handled = True
                                RichTextBox1.SelectionStart = intTrackPos + TabSpace - 1
                                TrackCaret = RichTextBox1.SelectionStart
                                RichTextBox1.Select(TrackCaret, 0)
                            Else
                                e.Handled = False
                                RichTextBox1.Select(TrackCaret, 0)
                                Exit While
                            End If

                            intTrackPos += 1
                        End While

                    End If

                End If

            ElseIf e.KeyCode = Keys.Left Then

                If RichTextBox1.SelectionStart > 0 Then
                    Dim intTrackPos = RichTextBox1.SelectionStart - 1

                    '---> Added Code Starts
                    If blnSelectedText Or RichTextBox1.Text.Substring(RichTextBox1.SelectionStart - 1, 1) = " " Then
                        If e.Shift = True And RichTextBox1.Text.Substring(RichTextBox1.SelectionStart - RichTextBox1.SelectionLength, 1) = " " Then
                            'This is selecting in Forward Direction, we need a way to select backwards
                            'RichTextBox1.Select(RichTextBox1.SelectionStart, RichTextBox1.SelectionLength + TabSpace - 1)
                        End If
                        Exit Sub
                    End If
                    '---> Added Code Ends

                    If Not blnSelectedText Then

                        While intTrackPos >= 0

                            If RichTextBox1.Text.Substring(intTrackPos, 1) = " " Then
                                e.Handled = True
                                RichTextBox1.SelectionStart = intTrackPos
                                TrackCaret = RichTextBox1.SelectionStart
                                RichTextBox1.Select(TrackCaret, 0)
                            Else
                                e.Handled = False
                                RichTextBox1.Select(TrackCaret, 0)
                                Exit While
                            End If
                            intTrackPos -= 1
                        End While

                    End If

                End If

            ElseIf e.KeyCode = Keys.Delete Then

                Try

                    If Not TrackCaret = RichTextBox1.Text.Length Then

                        If RichTextBox1.Text.Substring(RichTextBox1.SelectionStart, 1) = Chr(187) Then
                            e.Handled = True
                            RichTextBox1.Text = RichTextBox1.Text.Remove(TrackCaret, 5)
                            RichTextBox1.Select(TrackCaret, 0)
                            ColorizeText()
                        Else
                            e.Handled = False
                        End If

                    Else
                        e.Handled = False
                    End If


                Catch ex As ArgumentOutOfRangeException
                    MsgBox("Key delete: " + ex.Message)
                End Try

            ElseIf e.KeyCode = Keys.Back Then

                Try

                    If RichTextBox1.SelectionStart > 0 Then
                        TrackCaret = RichTextBox1.SelectionStart - 1
                        Dim intOrigPos As Integer = TrackCaret
                        Dim blnStop As Boolean = False

                        If RichTextBox1.Text.Substring(TrackCaret, 1) = " " Then
                            e.Handled = True
                            TrackCaret = RichTextBox1.SelectionStart - 5
                            RichTextBox1.Text = RichTextBox1.Text.Remove(TrackCaret, 5)
                            RichTextBox1.Select(intOrigPos - 4, 0)
                            ColorizeText()
                        Else
                            e.Handled = False
                        End If

                    Else
                        e.Handled = False
                    End If

                Catch ex As ArgumentOutOfRangeException
                    MsgBox("Key back: " + ex.Message)
                End Try

            End If

        End If

    End Sub
0
 
mesterakAuthor Commented:
I made some modifications to your updated code and ended up adding yet more handling via the KeyUp event in addition to changing the KeyDown event code again.  Using the left and right arrows for selecting text should work correctly now although it appears caret movement is a little slow.  Additionally, I have added code to unselect all text if you attempt to span across rows when the selected text starts or ends with a space.  This was the best way I could deal with having space characters belonging to the tab string in the selected text...do you think there is a better way?  I will award you the points right now, but please replace your code with the code below and retest.  Also, please reply with code changes or optimizations and let me know how well the code works for you.  Thank-you for working through this with me!

Imports System.Text
Imports System.Text.RegularExpressions

Public Class Form1
    Inherits System.Windows.Forms.Form

#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.
    Friend WithEvents RichTextBox1 As System.Windows.Forms.RichTextBox
    Friend WithEvents CheckBox1 As System.Windows.Forms.CheckBox
    Friend WithEvents StatusBar1 As System.Windows.Forms.StatusBar
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.RichTextBox1 = New System.Windows.Forms.RichTextBox
        Me.CheckBox1 = New System.Windows.Forms.CheckBox
        Me.StatusBar1 = New System.Windows.Forms.StatusBar
        Me.SuspendLayout()
        '
        'RichTextBox1
        '
        Me.RichTextBox1.AcceptsTab = True
        Me.RichTextBox1.BackColor = System.Drawing.Color.White
        Me.RichTextBox1.Font = New System.Drawing.Font("Courier New", 9.75!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Me.RichTextBox1.ForeColor = System.Drawing.Color.MediumBlue
        Me.RichTextBox1.Location = New System.Drawing.Point(24, 40)
        Me.RichTextBox1.Name = "RichTextBox1"
        Me.RichTextBox1.Size = New System.Drawing.Size(368, 160)
        Me.RichTextBox1.TabIndex = 0
        Me.RichTextBox1.Text = ""
        '
        'CheckBox1
        '
        Me.CheckBox1.Font = New System.Drawing.Font("Arial", 9.75!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
        Me.CheckBox1.Location = New System.Drawing.Point(24, 8)
        Me.CheckBox1.Name = "CheckBox1"
        Me.CheckBox1.Size = New System.Drawing.Size(168, 24)
        Me.CheckBox1.TabIndex = 1
        Me.CheckBox1.Text = "View typed spaces"
        '
        'StatusBar1
        '
        Me.StatusBar1.Location = New System.Drawing.Point(0, 285)
        Me.StatusBar1.Name = "StatusBar1"
        Me.StatusBar1.Size = New System.Drawing.Size(416, 16)
        Me.StatusBar1.TabIndex = 2
        Me.StatusBar1.Text = "StatusBar1"
        '
        'Form1
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(416, 301)
        Me.Controls.Add(Me.StatusBar1)
        Me.Controls.Add(Me.CheckBox1)
        Me.Controls.Add(Me.RichTextBox1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Private blnReplaceSpaces As Boolean = False
    Private TrackCaret As Integer = 0
    Private Const TabSpace As Integer = 5
    Private intLastCol As Integer = 1
    Private intNewCol As Integer = 1

    Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged
        RichTextBox1.Focus()
        TrackCaret = RichTextBox1.SelectionStart

        If CheckBox1.CheckState = CheckState.Checked Then
            blnReplaceSpaces = True

            If RichTextBox1.Text.Length > 0 Then
                Dim tmpString As String = RichTextBox1.Text
                tmpString = tmpString.Replace(Chr(32), Chr(149))
                tmpstring = tmpstring.Replace(Chr(9), Chr(187) + Space(TabSpace - 1))
                RichTextBox1.Text = tmpstring

                Dim Index As Integer = 0

                While Index < RichTextBox1.Text.Length

                    If RichTextBox1.Text.Substring(Index, 1) = Chr(149) Or RichTextBox1.Text.Substring(Index, 1) = Chr(187) Then
                        RichTextBox1.SelectionStart = Index
                        RichTextBox1.SelectionLength = 1
                        RichTextBox1.SelectionColor = Color.Peru
                    End If

                    Index += 1
                End While

                RichTextBox1.SelectionStart = TrackCaret
                RichTextBox1.Select(TrackCaret, 0)
                RichTextBox1.Focus()
            End If

        Else
            blnReplaceSpaces = False

            If RichTextBox1.Text.Length > 0 Then
                Dim tmpString As String = RichTextBox1.Text
                tmpString = tmpstring.Replace(Chr(187) + Space(TabSpace - 1), Chr(9))
                tmpString = tmpString.Replace(Chr(149), Chr(32))
                RichTextBox1.Text = tmpstring
                RichTextBox1.SelectAll()
                RichTextBox1.SelectionColor = Color.MediumBlue
                RichTextBox1.SelectionStart = TrackCaret
                RichTextBox1.Select(TrackCaret, 0)
                RichTextBox1.Focus()
            End If

        End If

        SendKeys.Send("{HOME}")
    End Sub

    Private Sub RichTextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles RichTextBox1.KeyPress

        If e.KeyChar = Chr(32) And blnReplaceSpaces = True Then
            e.Handled = True
            RichTextBox1.SelectedText = Chr(149)
            TrackCaret = RichTextBox1.SelectionStart
            RichTextBox1.SelectionStart = TrackCaret - 1
            RichTextBox1.SelectionLength = 1
            RichTextBox1.SelectionColor = Color.Peru
            RichTextBox1.Select(TrackCaret, 0)
            RichTextBox1.SelectionColor = Color.MediumBlue
        ElseIf e.KeyChar = Chr(9) And blnReplaceSpaces = True Then
            e.Handled = True
            RichTextBox1.SelectedText = Chr(187) + Space(TabSpace - 1)
            TrackCaret = RichTextBox1.SelectionStart
            RichTextBox1.SelectionStart = TrackCaret - TabSpace
            RichTextBox1.SelectionLength = 1
            RichTextBox1.SelectionColor = Color.Peru
            RichTextBox1.Select(TrackCaret, 0)
            RichTextBox1.SelectionColor = Color.MediumBlue
        ElseIf e.KeyChar = Chr(9) And blnReplaceSpaces = False Then
            e.Handled = True
            RichTextBox1.SelectedText = Chr(9)
            TrackCaret = RichTextBox1.SelectionStart
            RichTextBox1.SelectionStart = TrackCaret - 1
            RichTextBox1.SelectionLength = 1
            RichTextBox1.Select(TrackCaret, 0)
        ElseIf Not e.KeyChar = Chr(149) And Not e.KeyChar = Chr(187) And Not e.KeyChar = Chr(8) And Not e.KeyChar = vbCr Then
            e.Handled = True
            RichTextBox1.SelectedText = e.KeyChar
            TrackCaret = RichTextBox1.SelectionStart
            RichTextBox1.SelectionStart = TrackCaret - 1
            RichTextBox1.SelectionLength = 1
            RichTextBox1.SelectionColor = Color.MediumBlue
            RichTextBox1.Select(TrackCaret, 0)
            RichTextBox1.SelectionColor = Color.MediumBlue
        End If

    End Sub

    Private Sub RichTextBox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles RichTextBox1.KeyDown

        If blnReplaceSpaces = True Then
            TrackCaret = RichTextBox1.SelectionStart
            Dim blnSelectedText As Boolean = False

            If RichTextBox1.SelectedText.Length > 0 Then blnSelectedText = True

            If e.KeyCode = Keys.Right Then
                Dim intLength = RichTextBox1.Text.Length

                If RichTextBox1.SelectionStart >= 0 And RichTextBox1.SelectionStart < intLength Then
                    Dim intTrackPos = RichTextBox1.SelectionStart

                    If Not blnSelectedText And e.Shift = False Then

                        While intTrackPos < intLength

                            If RichTextBox1.Text.Substring(intTrackPos, 1) = Chr(187) Then
                                e.Handled = True
                                RichTextBox1.SelectionStart = intTrackPos + TabSpace - 1
                                TrackCaret = RichTextBox1.SelectionStart
                                RichTextBox1.Select(TrackCaret, 0)
                            Else
                                e.Handled = False
                                RichTextBox1.Select(TrackCaret, 0)
                                Exit While
                            End If

                            intTrackPos += 1
                        End While

                    End If

                End If

            ElseIf e.KeyCode = Keys.Left Then

                If RichTextBox1.SelectionStart > 0 Then
                    Dim intTrackPos = RichTextBox1.SelectionStart - 1

                    If Not blnSelectedText And e.Shift = False Then

                        While intTrackPos >= 0

                            If RichTextBox1.Text.Substring(intTrackPos, 1) = " " Then
                                e.Handled = True
                                RichTextBox1.SelectionStart = intTrackPos
                                TrackCaret = RichTextBox1.SelectionStart
                                RichTextBox1.Select(TrackCaret, 0)
                            Else
                                e.Handled = False
                                RichTextBox1.Select(TrackCaret, 0)
                                Exit While
                            End If

                            intTrackPos -= 1
                        End While

                    End If

                End If

            ElseIf e.KeyCode = Keys.Delete Then

                Try

                    If Not TrackCaret = RichTextBox1.Text.Length Then

                        If RichTextBox1.Text.Substring(RichTextBox1.SelectionStart, 1) = Chr(187) Then
                            e.Handled = True
                            RichTextBox1.Text = RichTextBox1.Text.Remove(TrackCaret, 5)
                            RichTextBox1.Select(TrackCaret, 0)
                            ColorizeText()
                        Else
                            e.Handled = False
                        End If

                    Else
                        e.Handled = False
                    End If


                Catch ex As ArgumentOutOfRangeException
                    MsgBox("Key delete: " + ex.Message)
                End Try

            ElseIf e.KeyCode = Keys.Back Then

                Try

                    If RichTextBox1.SelectionStart > 0 Then
                        TrackCaret = RichTextBox1.SelectionStart - 1
                        Dim intOrigPos As Integer = TrackCaret
                        Dim blnStop As Boolean = False

                        If RichTextBox1.Text.Substring(TrackCaret, 1) = " " Then
                            e.Handled = True
                            TrackCaret = RichTextBox1.SelectionStart - 5
                            RichTextBox1.Text = RichTextBox1.Text.Remove(TrackCaret, 5)
                            RichTextBox1.Select(intOrigPos - 4, 0)
                            ColorizeText()
                        Else
                            e.Handled = False
                        End If

                    Else
                        e.Handled = False
                    End If

                Catch ex As ArgumentOutOfRangeException
                    MsgBox("Key back: " + ex.Message)
                End Try

            End If

        End If

        intLastCol = intNewCol
    End Sub

    Private Sub RichTextBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles RichTextBox1.MouseUp

        If blnReplaceSpaces = True Then

            If RichTextBox1.SelectedText.Length = 0 Then
                Dim Index As Integer
                Index = Me.RichTextBox1.GetCharIndexFromPosition(New Point(e.X, e.Y))

                If Index > 0 And Index < RichTextBox1.TextLength And RichTextBox1.SelectedText.Length = 0 Then
                    SendKeys.SendWait("{LEFT}")
                    SendKeys.Send("{RIGHT}")
                End If

            Else

                If RichTextBox1.SelectedText.StartsWith(" ") Then
                    RichTextBox1.SelectionLength = 0
                    SendKeys.SendWait("{LEFT}")
                    SendKeys.Send("{RIGHT}")
                ElseIf RichTextBox1.SelectedText.EndsWith(" ") And RichTextBox1.SelectionStart + RichTextBox1.SelectedText.Length < RichTextBox1.TextLength Then

                    If RichTextBox1.Text.Substring(RichTextBox1.SelectionStart + RichTextBox1.SelectedText.Length + 1, 1) = " " Then
                        RichTextBox1.SelectionLength = 0
                        SendKeys.SendWait("{LEFT}")
                        SendKeys.Send("{RIGHT}")
                    End If

                End If

            End If

        End If


    End Sub

    Public Sub CaretMoved(ByVal sender As Object, ByVal e As EventArgs)
        Dim SLen As Integer = 0
        Dim G As System.Drawing.Graphics = RichTextBox1.CreateGraphics
        Dim Rows As Integer = RichTextBox1.GetLineFromCharIndex(RichTextBox1.SelectionStart)
        Dim Cols As Integer = RichTextBox1.SelectionStart
        Dim I As Integer = 0

        While I < RichTextBox1.Lines.GetLength(0)
            SLen += RichTextBox1.Lines(I).Length + 1
            If SLen > Cols Then
                ' Break
            End If
            System.Math.Min(System.Threading.Interlocked.Increment(I), I - 1)
        End While

        If (I = RichTextBox1.Lines.GetLength(0) - 1) AndAlso (RichTextBox1.Lines(I) = "") Then
            Cols = 0
        Else
            Dim P As Point = RichTextBox1.GetPositionFromCharIndex(Cols)
            Cols -= RichTextBox1.GetCharIndexFromPosition(New Point(0, P.Y))
        End If

        intNewCol = Cols + 1
        StatusBar1.Text = "Col: " + (Cols + 1).ToString
        StatusBar1.Text = StatusBar1.Text + " Row: " + (Rows + 1).ToString
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        AddHandler RichTextBox1.SelectionChanged, AddressOf CaretMoved
    End Sub

    Private Sub ColorizeText()
        Dim Index As Integer = 0
        TrackCaret = RichTextBox1.SelectionStart

        While Index < RichTextBox1.Text.Length

            If RichTextBox1.Text.Substring(Index, 1) = Chr(149) Or RichTextBox1.Text.Substring(Index, 1) = Chr(187) Then
                RichTextBox1.SelectionStart = Index
                RichTextBox1.SelectionLength = 1
                RichTextBox1.SelectionColor = Color.Peru
            End If

            Index += 1
        End While

        RichTextBox1.Select(TrackCaret, 0)
    End Sub

    Private Sub RichTextBox1_KeyUp(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles RichTextBox1.KeyUp

        If e.Shift And blnReplaceSpaces And RichTextBox1.SelectedText.Length > 0 Then

            If e.KeyCode = e.KeyCode.Right Then

                If intNewCol = intLastCol Then

                    If RichTextBox1.SelectedText.EndsWith(" ") Or RichTextBox1.SelectedText.EndsWith(Chr(187)) Then

                        If RichTextBox1.SelectedText.EndsWith(" ") Then

                            If intNewCol + RichTextBox1.SelectedText.Length < RichTextBox1.TextLength Then

                                If RichTextBox1.Text.Substring(RichTextBox1.SelectionStart + RichTextBox1.SelectedText.Length, 1) = " " Then
                                    SendKeys.Send("{RIGHT}")
                                End If

                            End If

                        Else
                            SendKeys.Send("{RIGHT}")
                        End If

                    End If

                Else

                    If RichTextBox1.SelectedText.StartsWith(" ") Then
                        SendKeys.Send("{RIGHT}")
                    End If

                End If

            End If

            If e.KeyCode = e.KeyCode.Left Then

                If intNewCol = intLastCol Then

                    If RichTextBox1.SelectedText.EndsWith(" ") Or RichTextBox1.SelectedText.EndsWith(Chr(187)) Then
                        SendKeys.Send("{LEFT}")
                    End If

                Else

                    If RichTextBox1.SelectedText.StartsWith(" ") Then
                        SendKeys.Send("{LEFT}")
                    End If

                End If

            End If

            If e.KeyCode = e.KeyCode.Up Or e.KeyCode = e.KeyCode.Down Then

                If RichTextBox1.SelectedText.StartsWith(" ") Then
                    RichTextBox1.SelectionLength = 0
                    SendKeys.SendWait("{LEFT}")
                    SendKeys.Send("{RIGHT}")
                ElseIf RichTextBox1.SelectedText.EndsWith(" ") And RichTextBox1.SelectionStart + RichTextBox1.SelectedText.Length < RichTextBox1.TextLength Then

                    If RichTextBox1.Text.Substring(RichTextBox1.SelectionStart + RichTextBox1.SelectedText.Length + 1, 1) = " " Then
                        RichTextBox1.SelectionLength = 0
                        SendKeys.SendWait("{LEFT}")
                        SendKeys.Send("{RIGHT}")
                    End If

                End If

            End If

        End If

    End Sub

End Class


0
 
arif_eqbalCommented:
That's perfect
The multiline thing is also working just fine.

When I select using Mouse and I start or end at a space it deselects. This is fine but if you analyse the same behaviour with Arrow key, it would not Deslect rather it would shift the start point (or the end point) so that the Tab is either included or excluded but the rest of the selection does not go.
You can even have this behaviour for the Mouse select also. However if it is too much trouble even the current scheme of things are fine.

Thanks
0
 
mesterakAuthor Commented:
It is livable, but I did find that the method used to colorize the text is very very slow if you have a lot of text.  I suppose I need to look into some type of syntax highlighting solution that runs cleaner and faster vs. iterating through the entire richtextbox text to fix coloring.
0

Featured Post

Vote for the Most Valuable Expert

It’s time to recognize experts that go above and beyond with helpful solutions and engagement on site. Choose from the top experts in the Hall of Fame or on the right rail of your favorite topic page. Look for the blue “Nominate” button on their profile to vote.

  • 7
  • 4
Tackle projects and never again get stuck behind a technical roadblock.
Join Now