Visual Basic.NET 2008 > Windows Controls in VB.NET

The TextEditor Project - TextBox Control in Visual Basic 2008

The TextEditor application, shown in Figure 4.2, demonstrates most of the TextBox control's properties and methods described so far. TextEditor is a basic text editor that you can incorporate into your programs and customize for special applications. The TextEditor project's main form is covered by a TextBox control, whose size is adjusted every time the user resizes the form. This feature doesn't require any programming — just set the Dock property of the TextBox control to Fill.

The name of the application's main form is frmTextEditor, and the name of the Find & Replace dialog box is frmFind. You can design the two forms as shown in the figures of this chapter, or open the TextEditor project. To design the application's interface from scratch, place a MenuStrip control on the form and dock it to the top of the form. Then place a TextBox control on the main form, name it txtEditor, and set the following properties: Multiline to True, MaxLength to 0 (to edit text documents of any length), HideSelection to False (so that the selected text remains highlighted even when the main form doesn't have the focus), and Dock to Fill, so that it will fill the form.

VB.NET TextEditor Project Example

Figure 4.2 - VB.NET TextEditor Project Example

The menu bar of the form contains all the commands you'd expect to find in text-editing applications; they're listed in Table 4.1.

Table 4.1 - The TextEditor Form's Menu

Menu Command Description
File New Clears the text
  Open Loads a new text file from disk
  Save Saves the text to its file on disk
  Save As Saves the text with a new filename on disk
  Print Prints the text
  Exit Terminates the application
     
Edit Undo/Redo Undoes/redoes the last edit operation
  Copy Copies selected text to the Clipboard
  Cut Cuts the selected text
  Paste Pastes the Clipboard's contents to the editor
  Select All Selects all text in the control
  Find & Replace Displays a dialog box with Find and Replace options
     
Process Convert To Upper Converts selected text to uppercase
  Convert To Lower Converts selected text to lowercase
  Number Lines Numbers the text lines
     
Format Font Sets the text's font, size, and attributes
  Page Color Sets the control's background color
  Text Color Sets the color of the text
  WordWrap Toggle menu item that turns text wrapping on and off

 

The File menu commands are implemented with the Open and Save As dialog boxes, the Font command with the Font dialog box, and the Color command with the Color dialog box. These dialog boxes are discussed in the following chapters, and as you'll see, you don't have to design them yourself. All you have to do is place a control on the form and set a few properties; the Framework takes it from there. The application will display the standard Open File/Save File/Font/Color dialog boxes, in which the user can select or specify a filename or select a font or color. Of course, we'll provide a few lines of code to actually move the text into a file (or read it from a file and display it on the control), change the control's background color, and so on.

The Editing Commands

The options on the Edit menu move the selected text to and from the Clipboard. For the TextEditor application, all you need to know about the Clipboard are the SetText method, which places the currently selected text on the Clipboard, and the GetText method, which retrieves information from the Clipboard (The Copy, Cut, and Paste operations can be used to exchange text with any other application).

The Copy command, for example, is implemented with a single line of code (txtEditor is the name of the TextBox control). The Cut command does the same, and it also clears the selected text. The code for these and for the Paste command, which assigns the contents of the Clipboard to the current selection, is presented in Listing 4.2.

Listing 4.2: The Cut, Copy, and Paste Commands

Private Sub EditCopyItem Click(...) Handles EditCopyItem.Click

If txtEditor.SelectionLength > 0 Then
Clipboard.SetText(txtEditor.SelectedText)
End If

End Sub

Private Sub EditCutItem Click(...) Handles EditCutItem.Click

Clipboard.SetText(txtEditor.SelectedText)
txtEditor.SelectedText = ""

End Sub

Private Sub EditPasteItem Click(...) Handles EditPasteItem.Click

If Clipboard.ContainsText Then
txtEditor.SelectedText = Clipboard.GetText
End If

End Sub

If no text is currently selected, the Clipboard's text is pasted at the pointer's current location. If the Clipboard contains a bitmap (placed there by another application) or any other type of data that the TextBox control can't handle, the paste operation will fail; that's why we handle the Paste operation with an If statement. You could provide some hint to the user by including an Else clause that informs them that the data on the Clipboard can't be used with a text-editing application.

The Process and Format Menus

The commands of the Process and Format menus are straightforward. The Format menu commands open the Font or Color dialog box and change the control's Font, ForeColor, and BackColor properties. You will learn how to use these controls in the following chapter. The Upper Case and Lower Case commands of the Process menu are also trivial: they select all the text, convert it to uppercase or lowercase, respectively, and assign the converted text to the control's SelectedText property with the following statements:

txtEditor.SelectedText = txtEditor.SelectedText.ToLower
txtEditor.SelectedText = txtEditor.SelectedText.ToUpper

Notice that the code uses the SelectedText property to convert only the selected text, not the entire document. The Number Lines command inserts a number in front of each text line and demonstrates how to process the individual lines of text on the control. However, it doesn't remove the line numbers, and there's no mechanism to prevent the user from editing the line numbers or inserting/deleting lines after they have been numbered. Use this feature to create a numbered listing or to number the lines of a file just before saving it or sharing it with another user. Listing 4.3 shows the Number Lines command's code and demonstrates how to iterate through the TextBox control's Lines array.

Listing 4.3: The Number Lines Command

Private Sub ProcessNumberLinesItem Click(...) Handles ProcessNumberLines.Click

Dim iLine As Integer
Dim newText As New System.Text.StringBuilder()

For iLine = 0 To txtEditor.Lines.Length - 1
newText.Append((iLine + 1).ToString & vbTab& txtEditor.Lines(iLine) & vbCrLf)
Next
txtEditor.SelectAll()
Clipboard.SetText(newText.ToString)
txtEditor.Paste()

End Sub

This event handler uses a StringBuilder variable. The StringBuilder class, which is discussed in detail in Chapter, "Designing Custom Windows Controls," is equivalent to the String class; it exposes similar methods and properties, but it's much faster at manipulating dynamic strings than the String class.

Search and Replace Operations

The last option in the Edit menu — and the most interesting — displays a Find & Replace dialog box (shown in Figure 4.2). This dialog box works like the similarly named dialog box of Microsoft Word and many other Windows applications. The buttons in the Find & Replace dialog box are relatively self-explanatory:

Find - The Find command locates the first instance of the specified string in the text after the cursor location. If a match is found, the Find Next, Replace, and Replace All buttons are enabled.

Find Next - This command locates the next instance of the string in the text. Initially, this button is disabled; it's enabled only after a successful Find operation.

Replace - This replaces the current selection with the replacement string and then locates the next instance of the same string in the text. Like the Find Next button, it's disabled until a successful Find operation occurs.

Replace All - This replaces all instances of the string specified in the Search For box with the string in the Replace With box.

Design a form like the one shown in Figure 4.2 and set its TopMost property to True. We want this form to remain on top of the main form, even when it doesn't have the focus.

Whether the search is case-sensitive or not depends on the status of the Case Sensitive CheckBox control. If the string is found in the control's text, the program highlights it by selecting it. In addition, the program calls the TextBox control's ScrollToCaret method to bring the selection into view. The Find Next button takes into consideration the location of the pointer and searches for a match after the current location. If the user moves the pointer somewhere else and then clicks the Find Next button, the program will locate the first instance of the string after the current location of the pointer — and not after the last match. Of course, you can always keep track of the location of each match and continue the search from this location. The Find button executes the code shown in Listing 4.4.

Listing 4.4: The Find Button

Private Sub bttnFind Click(...) Handles bttnFind.Click

Dim selStart As Integer

If chkCase.Checked = True Then
selStart = frmTextEditor.txtEditor.Text.IndexOf(searchWord.Text, StringComparison.Ordinal)
Else
selStart = frmTextEditor.txtEditor.Text.IndexOf(searchWord.Text, StringComparison.OrdinalIgnoreCase)
End If

If selStart = -1 Then
MsgBox("Can't find word")
Exit Sub
End If

frmTextEditor.txtEditor.Select(selStart, searchWord.Text.Length)
bttnFindNext.Enabled = True
bttnReplace.Enabled = True
bttnReplaceAll.Enabled = True
frmTextEditor.txtEditor.ScrollToCaret()

End Sub

The Find button examines the value of the chkCase CheckBox control, which specifies whether the search will be case-sensitive and calls the appropriate form of the IndexOf method. The first argument of this method is the string we're searching for; the second argument is the searchmode, and its value is a member of the StringComparison enumeration: Ordinal for case-sensitive searches and OrdinalIgnoreCase for case-insensitive searches. If the IndexOf method locates the string, the program selects it by calling the control's Select method with the appropriate arguments. If not, it displays a message. Notice that after a successful Find operation, the Find Next, Replace, and Replace All buttons on the form are enabled.

The code of the Find Next button is the same, but it starts searching at the character following the current selection. This way, the IndexOf method locates the next instance of the same string. Here's the statement that locates the next instance of the search argument:

selStart = frmTextEditor.txtEditor.Text.IndexOf( _
searchWord.Text, _
frmTextEditor.txtEditor.SelectionStart + 1, _
StringComparison.Ordinal)

The Replace button replaces the current selection with the replacement string and then locates the next instance of the find string. The Replace All button replaces all instances of the search word in the document. Listing 4.5 presents the code behind the Replace and Replace All buttons.

Listing 4.5: The Replace and Replace All Operations

Private Sub bttnReplace Click(...) Handles bttnReplace.Click

If frmTextEditor.txtEditor.SelectedText <> "" Then
frmTextEditor.txtEditor.SelectedText = replaceWord.Text
End If
bttnFindNext Click(sender, e)

End Sub

Private Sub bttnReplaceAll Click(...) Handles bttnReplaceAll.Click

Dim curPos, curSel As Integer
curPos = frmTextEditor.txtEditor.SelectionStart
curSel = frmTextEditor.txtEditor.SelectionLength
frmTextEditor.txtEditor.Text =
frmTextEditor.txtEditor.Text.Replace(
searchWord.Text.Trim, replaceWord.Text.Trim)
frmTextEditor.txtEditor.SelectionStart = curPos
frmTextEditor.txtEditor.SelectionLength = curSel

End Sub

The Replace method is case-sensitive, which means that it replaces instances of the search argument in the text that have the exact same spelling as its first argument. For a case-insensitive replace operation, you must write the code to perform consecutive case-insensitive searchand-replace operations. Alternatively, you can use the Replace built-in function to perform case-insensitive searches. Here's how you'd call the Replace function to perform a case-insensitive replace operation:

Replace(frmTextEditor.txtEditor.Text, searchWord.Text.Trim, _
replaceWord.Text.Trim, , , CompareMethod.Text)

The last, optional, argument determines whether the search will be case-sensitive (CompareMethod.Binary) or case-insensitive (CompareMethod.Text).

The Undo/Redo Commands

The Undo command (shown in Listing 4.6) is implemented with a call to the Undo method. However, because the Undo method works like a toggle, we must also toggle its caption from Undo to Redo (and vice versa) each time the command is activated.

Listing 4.6: The Undo/Redo Command of the EditMenu

Private Sub EditUndoItem Click(...) Handles EditUndoItem.Click

If EditUndoItem.Text = "Undo" Then
If txtEditor.CanUndo Then
txtEditor.Undo()
EditUndoItem.Text = "Redo"
End If
Else
If txtEditor.CanUndo Then
txtEditor.Undo()
EditUndoItem.Text = "Undo"
End If
End If

End Sub

If you edit the text after an undo operation, you can no longer redo the last undo operation. This means that as soon as the contents of the TextBox control change, the caption of the first command in the Edit menu must become Undo, even if it's Redo at the time. The Redo command is available only after undoing an operation and before editing the text. So, how do we know that the text has been edited? The TextBox control fires the TextChanged event every time its contents change. We'll use this event to restore the caption of the Undo/Redo command to Undo. Insert the following statement in the TextChanged event of the TextBox control:

EditUndoItem.Text = "Undo"

The TextBox control can't provide more-granular undo operations— unlike Word, which keeps track of user actions (insertions, deletions, replacements, and so on) and then undoes them in steps. If you need a more-granular undo feature, you should use the RichTextBox control. The RichTextBox control can display formatted text, but it can also be used as an enhanced TextBox control. By the way, setting the menu item's caption from within the TextChanged event handler is an overkill, because this event takes place every time the user presses a key. However, the operation takes no time at all and doesn't make the application less responsive. A better choice would be the DropDownOpening event of the editFormat item, which is fired every time the user opens the Edit menu.

More Lessons on VB.NET TextBox

Table of Contents





     
 
W3computing.com Copyright 2011 All Rights Reserved
 
  Home | Useful links | Contact us