Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
(ebook) Visual Studio .NET Mastering Visual Basic.pdf
Скачиваний:
136
Добавлен:
17.08.2013
Размер:
15.38 Mб
Скачать

THE RICHTEXTBOX CONTROL 317

Formatting URLs

A new feature built into the RichTextBox control is the automatic formatting of URLs embedded in the text. To enable this feature, set the DetectURLs property to True. Then, as soon as the control determines that you’re entering a URL (usually after you enter the three Ws and the following period), it will format the text as a hyperlink. When the pointer rests over a hyperlink, its shape turns into a hand, just as it would in Internet Explorer. Run the RTFDemo project, enter a URL like www.sybex.com, and see how the RichTextBox control handles it.

In addition to formatting the URL, the RichTextBox control triggers the LinkClicked event when a hyperlink is clicked. To display the corresponding page from within your code, enter the following statement in the LinkClicked event handler:

Private Sub RichTextBox1_LinkClicked(ByVal sender As Object, _

ByVal e As System.Windows.Forms.LinkClickedEventArgs) _ Handles RichTextBox1.LinkClicked

System.Diagnostics.Process.Start(e.LinkText) End Sub

The System.Diagnostics.Process class provides the Start method, which starts an application. You can specify either the name of the executable or the path of a file. The Start method will look up the associated application and start it. As you can see, handling embedded URLs with the RichTextBox control is almost trivial.

Whatever application or file you specify in the Start method (Internet Explorer, for example) will run independently of your application, and the user may navigate to any other site, or close the browser and return to your application.

VB.NET at Work: The RTFPad Project

Creating a functional, even fancy, word processor based on the RichTextBox control is quite simple. The challenge is to provide a convenient interface that lets the user select text, apply attributes and styles to it, and then set the control’s properties accordingly. This chapter’s application does just that. It’s called RTFPad, and you can find it in this chapter’s folder on the CD.

The RTFPad application (see Figure 7.9) is based on the TextPad application developed in Chapter 6. It contains the same text-editing commands and some additional text-formatting commands that can only be implemented with the RichTextBox control; for example, it allows you to mix font styles in the text. This section examines the code and discusses a few topics unique to this application’s implementation with the RichTextBox control.

The two TrackBar controls above the RichTextBox control manipulate the indentation of the text. We’ve already explored this arrangement in the discussion of the TrackBar control in Chapter 6, but let’s review the operation of the two controls again. Each TrackBar control has a width of 816 pixels, which is equivalent to 8.5 inches on a monitor with a resolution of 96 dpi (dots per inch). The height of the TrackBar controls is 42 pixels and, unfortunately, they can’t be made smaller. The Minimum and Maximum properties of the control are of no significance, because all we really care about is the relative value of the control. Each time the user slides the top TrackBar control, the code sets the SelectionIndent property to the proper percentage of the control’s width. Because the SelectionHangingIndent includes the value of the SelectionIndent property, it also adjusts the setting of the SelectionHangingIndent property. Listing 7.4 is the code that’s executed when the upper TrackBar control is scrolled.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

318 Chapter 7 MORE WINDOWS CONTROLS

Listing 7.4: Setting the SelectionIndent Property

Private Sub TrackBar1_Scroll(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles TrackBar1.Scroll

Editor.SelectionIndent = Editor.Width * (TrackBar1.Value / TrackBar1.Maximum) Editor.SelectionHangingIndent = Editor.Width * _

(TrackBar2.Value / TrackBar2.Maximum) - Editor.SelectionIndent

End Sub

The second TrackBar control controls the hanging indentation of the selected text (the indentation of all text lines after the first one). Its Scroll event handler is presented in Listing 7.5.

Listing 7.5: Setting the SelectionHangingIndent Property

Private Sub TrackBar2_Scroll(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles TrackBar2.Scroll Editor.SelectionHangingIndent = Editor.Width * _

(TrackBar2.Value / TrackBar2.Maximum) - Editor.SelectionIndent

End Sub

Enter some text in the control, select one or more paragraphs, and check out the operation of the two sliders.

The Scroll events of the two TrackBar controls adjust the text’s indentation. The opposite action must take place when the user rests the pointer on another paragraph: the sliders’ positions must be adjusted to reflect the new indentation of the text. The selection of a new paragraph is signaled to the application by the SelChange event. The statements of Listing 7.6, which are executed from within the SelChange event, adjust the two slider controls to reflect the indentation of the text.

Listing 7.6: Setting the Slider Controls

Private Sub Editor_SelectionChanged(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles Editor.SelectionChanged

If Editor.SelectionIndent = Nothing Then

TrackBar1.Value = TrackBar1.Minimum

TrackBar2.Value = TrackBar2.Minimum

Else

TrackBar1.Value = Editor.SelectionIndent * TrackBar1.Maximum / _

Editor.Width

TrackBar2.Value = (Editor.SelectionHangingIndent / Editor.Width) * _

TrackBar2.Maximum + TrackBar1.Value

End If

End Sub

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

THE RICHTEXTBOX CONTROL 319

If the user selects multiple paragraphs with different indentations, the SelectionIndent property returns Nothing. The code examines the value of the SelectionIndent property and, if it’s Nothing, it moves both controls to the left edge. This way, the user can slide the controls and set the indentations for multiple paragraphs. Or you can set the sliders according to the indentation of the first or last paragraph in the selection. Some applications make the handles gray to indicate that the selected text doesn’t have uniform indentation, but unfortunately you can’t gray the sliders and keep them enabled. Of course, you can always design a custom control. The TrackBar controls are too tall for this type of interface and can’t be made very narrow (as a result, the interface of the RTFPad application isn’t very elegant).

The File Menu

The RTFPad application’s File menu contains the usual Open, Save, and Save As commands, which are implemented with the LoadFile and SaveFile methods. Listing 7.7 shows the implementation of the Open command in the File menu.

Listing 7.7: The Open Command

Private Sub FileOpen_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles FileOpen.Click If DiscardChanges() Then

OpenFileDialog1.Filter = “RTF Files|*.RTF|DOC Files|” & _ “*.DOC|Text Files|*.TXT|All Files|*.*”

If OpenFileDialog1.ShowDialog() = DialogResult.OK Then fName = OpenFileDialog1.FileName Editor.LoadFile(fName)

Editor.Modified = False End If

End If End Sub

The fName variable is declared on the Form level and holds the name of the currently open file. It’s set every time a new file is successfully opened and used by the Save command to automatically save the open file, without prompting the user for a filename.

DiscardChanges() is a function that returns a Boolean value, depending on whether the control’s contents can be discarded or not. The function starts by examining the Editor control’s Modified property. If True, it prompts the user as to whether he wants to discard the edits. Depending on the value of the Modified property and the user’s response, the function returns a Boolean value. If the DiscardChanges() function returns True, the program goes on and opens a new document. If the function returns False, the handler exits. Listing 7.8 shows the DiscardChanges() function.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

320 Chapter 7 MORE WINDOWS CONTROLS

Listing 7.8: The DiscardChanges() Function

Function DiscardChanges() As Boolean If Editor.Modified Then

Dim reply As MsgBoxResult

reply = MsgBox(“Text hasn’t been saved. Discard changes?”, _ MsgBoxStyle.YesNo)

If reply = MsgBoxResult.No Then Return False

Else

Return True End If

Else

Return True End If

End Function

The Modified property becomes True after typing the first character and isn’t reset back to False. The RichTextBox control doesn’t handle this property very intelligently and doesn’t reset it to False even after saving the control’s contents to a file. The application’s code sets the Editor.Modified property to False after creating a new document, as well as after saving the current document.

The Save As command (Listing 7.9) prompts the user for a filename and then stores the Editor control’s contents to the specified file. It also sets the fName variable to the file’s path, so that the Save command can use it. The fName variable is declared at the beginning of the code, outside any procedure.

Listing 7.9: The Save As Command

Private Sub FileSaveAs_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles FileSaveAs.Click SaveFileDialog1.Filter = “RTF Files|*.RTF|DOC Files|” & _

“*.DOC|Text Files|*.TXT|All Files|*.*” SaveFileDialog1.DefaultExt = “RTF”

If SaveFileDialog1.ShowDialog() = DialogResult.OK Then fName = SaveFileDialog1.FileName Editor.SaveFile(fName)

Editor.Modified = False End If

End Sub

The Save command’s code is similar, only it doesn’t prompt the user for a filename. It calls the SaveFile method passing the fName variable as argument. If the fName variable has no value (in other words, if a user attempts to save a new document with the Save command), then the code activates the event handler of the Save As command automatically. It also resets the control’s Modified property to False. The code behind the Save command is shown in Listing 7.10.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

THE RICHTEXTBOX CONTROL 321

Listing 7.10: The Save Command

Private Sub FileSave_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles FileSave.Click

If fName <> “” Then

Editor.SaveFile(fName)

Editor.Modified = False

Else

FileSaveAs_Click(sender, e)

End If

End Sub

The Edit Menu

The Edit menu contains the usual commands for exchanging data through the Clipboard (Copy, Cut, Paste), Undo/Redo commands, and a Find command to invoke the Find and Replace dialog box. All the commands are almost trivial, thanks to the functionality built into the control. The basic Cut, Copy, and Paste commands call the RichTextBox control’s Copy, Cut, and Paste methods to exchange information with other applications through the Clipboard. If you aren’t familiar with the Clipboard’s methods, all you need to know to follow this example are the SetText method, which copies a string to the Clipboard, and the GetText method, which copies the Clipboard’s contents to a string variable. The Copy, Cut, and Paste commands are shown in Listing 7.11.

Listing 7.11: The Copy, Cut, and Paste Commands

Private Sub EditCopy_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles EditCopy.Click

Editor.Copy()

End Sub

Private Sub EditCut_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles EditCut.Click

Editor.Cut()

End Sub

Private Sub EditPaste_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles EditPaste.Click

Try

Editor.Paste()

Catch exc As Exception

MsgBox(“Can’t paste current clipboard’s contents”)

End Try

End Sub

As you recall from the discussion of the Paste command, we can’t use the CanPaste method, because it’s not trivial; you have to handle each data type differently. By using the exception handler, we allow the user to paste all types of data the RichTextBox control can accept, and we display a message when an error occurs.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

322 Chapter 7 MORE WINDOWS CONTROLS

The Undo and Redo commands of the Edit menu are coded as follows. First, we must display the name of the action to be undone or redone in the Edit menu. When the Edit menu is selected, the Select event is fired. This event takes place before the Click event, so I’ve inserted a few lines of code that read the name of the most recent action that can be undone or redone and print it next to the Undo or Redo command. If there’s no such action, the program will disable the corresponding command. Listing 7.12 is the code that’s executed when the Edit menu is dropped.

Listing 7.12: Setting the Captions of the Undo and Redo Commands

Private Sub EditMenu_Select(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles EditMenu.Select

If Editor.UndoActionName <> “” Then

EditUndo.Text = “Undo “ & Editor.UndoActionName

EditUndo.Enabled = True

Else

EditUndo.Text = “Undo”

EditUndo.Enabled = False

End If

If Editor.RedoActionName <> “” Then

EditRedo.Text = “Redo “ & Editor.RedoActionName

EditRedo.Enabled = True

Else

EditRedo.Text = “Redo”

EditRedo.Enabled = False

End If

End Sub

When the user selects one of the Undo and Redo commands, we simply call the appropriate method from within the menu item’s Click event handler (Listing 7.13).

Listing 7.13: Undoing and Redoing Actions

Private Sub EditUndo_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles EditUndo.Click

If Editor.CanUndo Then Editor.Undo()

End Sub

Private Sub EditRedo_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles EditRedo.Click

If Editor.CanRedo Then Editor.Redo()

End Sub

Calling the CanUndo and CanRedo method is unnecessary, because if there’s no corresponding action the two menu items will be disabled, but an additional check is no harm. Should there be an “unknown” action that the control can’t undo, these If statements will prevent the control from attempting to perform the undo action.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

THE RICHTEXTBOX CONTROL 323

The Format Menu

The commands of the Format menu control the alignment of the text and the font attributes of the current selection. The Font command displays the Font dialog box and then assigns the font selected by the user to the current selection. Listing 7.14 shows the code behind the Font command.

Listing 7.14: The Font Command

Private Sub FormatFont_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles FormatFont.Click

If Not Editor.SelectionFont Is Nothing Then

FontDialog1.Font = Editor.SelectionFont

Else

FontDialog1.Font = Nothing

End If

If FontDialog1.ShowDialog() = DialogResult.OK Then

Editor.SelectionFont = FontDialog1.Font

End If

End Sub

Notice that the code preselects a font on the dialog box, which is the font of the current selection. If the current selection isn’t formatted with a single font, then no font is preselected. You can modify the code so that it displays the font of the first character in the selection.

To enable the Apply button of the Font dialog box, set the control’s ShowApply property to True and insert the following statement in its Apply event handler. Select the FontDialog1 control in the Objects drop-down list of the code editor, and then select the Apply event in the Events dropdown list. When the declaration of the event handler appears, insert the statement that applies the font selected on the Font dialog box to the current selection:

Private Sub FontDialog1_Apply(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles FontDialog1.Apply Editor.SelectionFont = FontDialog1.Font

End Sub

The options of the Align menu set the RichTextBox control’s SelectionAlignment property to different members of the HorizontalAlignment enumeration. The Align Left command, for example, is implemented with the following statement:

Editor.SelectionAlignment = HorizontalAlignment.Left

The Search & Replace Dialog Box

The Find command in the Edit menu opens the dialog box shown in Figure 7.14, which the user can use to perform various search and replace operations (whole-word or case-sensitive match, or both). The code behind the Command buttons on this form is quite similar to the code for the Search & Replace dialog box of the TextPad application, with one basic difference: it uses the control’s Find method. The Find method of the RichTextBox control performs all types of searches, and some of its options are not available with the InStr() function.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

324 Chapter 7 MORE WINDOWS CONTROLS

Figure 7.14

The Search & Replace dialog box of the RTFPad application

To invoke the Search & Replace dialog box (Listing 7.15), the Find command calls the Show method of a variable that represents the dialog box.

Listing 7.15: Displaying the Search & Replace Dialog Box

Private Sub EditFind_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles EditFind.Click If fndForm Is Nothing Then

fndForm = New FindForm() End If

fndForm.Show() End Sub

fndForm is declared on the Form level with the following statement:

Dim fndForm As FindForm

The dialog box should have access to the Editor control on the main form. To allow the dialog box to manipulate the RichTextBox control on the main form, the program declared a public shared variable with the following statement:

Public Shared RTFBox As RichTextBox

This variable is initialized to the Editor RichTextBox control in the form’s Load event handler, shown in Listing 7.16.

Listing 7.16: The Main Form’s Load Event Handler

Private Sub EditorForm_Load(ByVal sender As Object, _

ByVal e As System.EventArgs) Handles MyBase.Load

RTFBox = Editor

End Sub

The Find method of the RichTextBox control allows you to perform case-sensitive or -insensitive searches, as well as search for whole words only. These options are specified through an argument of the RichTextBoxFinds type. The SetSearchMode() function (Listing 7.17) examines the settings of the two check boxes at the bottom of the form and sets this option.

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com

THE RICHTEXTBOX CONTROL 325

Listing 7.17: Setting the Search Options

Function SetSearchMode() As RichTextBoxFinds Dim mode As RichTextBoxFinds

If chkCase.Checked = True Then

mode = RichTextBoxFinds.MatchCase Else

mode = RichTextBoxFinds.None End If

If chkWord.Checked = True Then

mode = mode Or RichTextBoxFinds.WholeWord Else

mode = mode Or RichTextBoxFinds.None End If

SetSearchMode = mode End Function

The Find and Find Next methods call this function to retrieve the constant that determines the type of the search specified by the user on the form. This value is then passed to the Find method. Listing 7.18 shows the code behind the Find and Find Next buttons.

Listing 7.18: The Find and Find Next Commands

Private Sub bttnFind_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles bttnFind.Click Dim wordAt As Integer

Dim srchMode As RichTextBoxFinds srchMode = SetSearchMode()

wordAt = EditorForm.RTFBox.Find(txtSearchWord.Text, 0, srchMode) If wordAt = -1 Then

MsgBox(“Can’t find word”) Exit Sub

End If

EditorForm.RTFBox.Select(wordAt, txtSearchWord.Text.Length) bttnFindNext.Enabled = True

bttnReplace.Enabled = True bttnReplaceAll.Enabled = True EditorForm.RTFBox.ScrollToCaret()

End Sub

Private Sub bttnFindNext_Click(ByVal sender As System.Object, _

ByVal e As System.EventArgs) Handles bttnFindNext.Click Dim selStart As Integer

Dim srchMode As CompareMethod srchMode = SetSearchMode()

selStart = InStr(EditorForm.RTFBox.SelectionStart + 2, _ EditorForm.RTFBox.Text, txtSearchWord.Text, srchMode)

Copyright ©2002 SYBEX, Inc., Alameda, CA

www.sybex.com