|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThis article describes an easy approach to building a simple word processor around an extended version of the
Whilst this project will not lead you to drop MS Word, it is a decent little word processor, and to that end, you may find a use for it. I have always kept one of these on hand, and have frequently tailored them to do things like provide a custom tool for viewing reports, error logs, and things of that nature when I wanted to integrate that feature into a product so that I could use it in lieu of doing something like shelling out a text file into Notepad. Doing so allows me to control the appearance of the application, the caption in the title bar of the form, etc.
Figure 1: The editor application in use Getting StartedIn order to get started, unzip the attachment, and load the solution into Visual Studio 2005. Examine the Solution Explorer, and note the files contained in the project:
Figure 2: The Solution Explorer showing the project files First, note that there are two separate projects contained in the solution. The first project is a class library entitled, “ExtendedRichTextBox”. That library contains a single control class, “ The second solution is the editor application itself (RichTextEditor). This application uses the extended rich text box control, and then to that, adds in all of the normal document manipulation techniques (such as font selection, indentation, and file IO support). Aside from the main application’s form (
Figure 3: Editor application Find dialog
Figure 4: Editor application Find and Replace dialog In addition to the form classes mentioned, the solution also contains a folder entitled “Graphics”; this folder contains all of the image files used to support the application’s menus and toolbar. Project ReferencesAside from the default references, there are a couple of additional references added. Most notably, the extended rich text box control library is added to allow for the use of the extended rich text box control. Figure 5 shows the references as they exist in the project.
Figure 5: Project references The Code: The Main Form ClassThe main form class (
The imports and the class declaration looks like this: Imports System.Drawing
Imports System.Drawing.Image
Public Class frmMain
The class declaration is plain enough, and does not inherit from or implement any base class or interface. I would emphasis here again that making use of Microsoft’s extended rich text box control greately reduces the amount of code necessary to support all of the methods used within this application. The declarations section is also very simple; the section contains the variables used throughout the application. The content is as follows: #Region "Declarations"
Private currentFile As String
Private checkPrint As Integer
#End Region
The “ The “ The next section of code is the primary block of code used by this application. The “ The first block of code in the menu region is used to create a new file: Private Sub NewToolStripMenuItem_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles NewToolStripMenuItem.Click
If rtbDoc.Modified Then
Dim answer As Integer
answer = MessageBox.Show("The current document has not" & _
" been saved, would you like to " & _
"continue without saving?", "Unsaved Document", _
MessageBoxButtons.YesNo, MessageBoxIcon.Question)
If answer = Windows.Forms.DialogResult.Yes Then
rtbDoc.Clear()
Else
Exit Sub
End If
Else
rtbDoc.Clear()
End If
currentFile = ""
Me.Text = "Editor: New Document"
End Sub
In this subroutine, prior to clearing the current document, the status of the current document is checked by using the control's “
Figure 6: Confirmation dialog shown after user requests a new document without saving changes The next subroutine is used to open an existing file into the rich text box control: Private Sub OpenToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles OpenToolStripMenuItem.Click
If rtbDoc.Modified Then
Dim answer As Integer
answer = MessageBox.Show("The current document has not" & _
" been saved, would you like to continue " & _
"without saving?", "Unsaved Document", _
MessageBoxButtons.YesNo, MessageBoxIcon.Question)
If answer = Windows.Forms.DialogResult.No Then
Exit Sub
Else
OpenFile()
End If
Else
OpenFile()
End If
End Sub
This subroutine works in a manner similar to the “new” subroutine discussed in the previous section. If the file has not been modified or if the user decides not to save the current modifications, the subroutine calls an Private Sub OpenFile()
OpenFileDialog1.Title = "RTE - Open File"
OpenFileDialog1.DefaultExt = "rtf"
OpenFileDialog1.Filter = "Rich Text Files|*.rtf|" & _
"Text Files|*.txt|HTML Files|" & _
"*.htm|All Files|*.*"
OpenFileDialog1.FilterIndex = 1
OpenFileDialog1.ShowDialog()
If OpenFileDialog1.FileName = "" Then Exit Sub
Dim strExt As String
strExt = System.IO.Path.GetExtension(OpenFileDialog1.FileName)
strExt = strExt.ToUpper()
Select Case strExt
Case ".RTF"
rtbDoc.LoadFile(OpenFileDialog1.FileName,
RichTextBoxStreamType.RichText)
Case Else
Dim txtReader As System.IO.StreamReader
txtReader = New
System.IO.StreamReader(OpenFileDialog1.FileName)
rtbDoc.Text = txtReader.ReadToEnd
txtReader.Close()
txtReader = Nothing
rtbDoc.SelectionStart = 0
rtbDoc.SelectionLength = 0
End Select
currentFile = OpenFileDialog1.FileName
rtbDoc.Modified = False
Me.Text = "Editor: " & currentFile.ToString()
End Sub
Figure 7: Open File dialog The first part of the The next item up is the “Save” menu option; it contains the following code: Private Sub SaveToolStripMenuItem_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles SaveToolStripMenuItem.Click
If currentFile = "" Then
SaveAsToolStripMenuItem_Click(Me, e)
Exit Sub
End If
Dim strExt As String
strExt = System.IO.Path.GetExtension(currentFile)
strExt = strExt.ToUpper()
Select Case strExt
Case ".RTF"
rtbDoc.SaveFile(currentFile)
Case Else
' to save as plain text
Dim txtWriter As System.IO.StreamWriter
txtWriter = New System.IO.StreamWriter(currentFile)
txtWriter.Write(rtbDoc.Text)
txtWriter.Close()
txtWriter = Nothing
rtbDoc.SelectionStart = 0
rtbDoc.SelectionLength = 0
rtbDoc.Modified = False
End Select
Me.Text = "Editor: " & currentFile.ToString()
End Sub
The “Save” function first checks to see if the “ With both the file open and file save methods used, if the file is anything other than a rich text file, the application will attempt to open or save it with a stream reader or stream writer; this will allow the application to work with any text file, not just RTF, TXT, or HTML files. That would permit you to use it with custom file types, or other things such as license files or error log files. The next subroutine addresses the “Save As” menu option; its code is as follows: Private Sub SaveAsToolStripMenuItem_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles SaveAsToolStripMenuItem.Click
SaveFileDialog1.Title = "RTE - Save File"
SaveFileDialog1.DefaultExt = "rtf"
SaveFileDialog1.Filter = "Rich Text Files|*.rtf|" & _
"Text Files|*.txt|HTML Files" & _
"|*.htm|All Files|*.*"
SaveFileDialog1.FilterIndex = 1
SaveFileDialog1.ShowDialog()
If SaveFileDialog1.FileName = "" Then Exit Sub
Dim strExt As String
strExt = System.IO.Path.GetExtension(SaveFileDialog1.FileName)
strExt = strExt.ToUpper()
Select Case strExt
Case ".RTF"
rtbDoc.SaveFile(SaveFileDialog1.FileName, _
RichTextBoxStreamType.RichText)
Case Else
Dim txtWriter As System.IO.StreamWriter
txtWriter = New
System.IO.StreamWriter(SaveFileDialog1.FileName)
txtWriter.Write(rtbDoc.Text)
txtWriter.Close()
txtWriter = Nothing
rtbDoc.SelectionStart = 0
rtbDoc.SelectionLength = 0
End Select
currentFile = SaveFileDialog1.FileName
rtbDoc.Modified = False
Me.Text = "Editor: " & currentFile.ToString()
End Sub
Figure 8: File menu options By now, this should look pretty familiar; in the code, a Save as file dialog box is configured and displayed to the user. The dialog will permit the user to save the file as RTF, TXT, or HTML. If the user saves the file as RTF, the control’s The next item in the code is the menu’s Exit call. It is used to terminate the application. Prior to closing the application, this subroutine checks to see if the current document has been modified and, if it has, it alerts the user and asks whether or not the document should be saved prior to closing it and the application. The code is as follows: Private Sub ExitToolStripMenuItem_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles ExitToolStripMenuItem.Click
If rtbDoc.Modified Then
Dim answer As Integer
answer = MessageBox.Show("The current document has not been" & _
" saved, would you like to continue without saving?", _
"Unsaved Document", MessageBoxButtons.YesNo, _
MessageBoxIcon.Question)
If answer = Windows.Forms.DialogResult.No Then
Exit Sub
Else
Application.Exit()
End If
Else
Application.Exit()
End If
End Sub
The next menu option addressed is the edit menu’s “Select All” function. Select All is a method embedded in the rich text box control, and therefore it may be called directly without writing any additional code to make the Select All happen; to use it, just call it as follows: Private Sub SelectAllToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles SelectAllToolStripMenuItem.Click
Try
rtbDoc.SelectAll()
Catch exc As Exception
MessageBox.Show("Unable to select all document content.", _
"RTE – Select", MessageBoxButtons.OK, _
MessageBoxIcon.Error)
End Try
End Sub
Following the edit menu’s “Select All” function, we have the cut, copy, and paste subroutines. Just as the Select All method exists within the rich text box control, so do these, and so you can call them directly in a manner similar to that used in Select All. For that reason, I am not going to show them here, but you can see the calls made in the example application if you’d care to take a look at them.
Figure 9: Edit menu options Next up is the menu option used to select the current font. This code merely uses a standard font dialog box to set the rich text box control’s Private Sub SelectFontToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles SelectFontToolStripMenuItem.Click
If Not rtbDoc.SelectionFont Is Nothing Then
FontDialog1.Font = rtbDoc.SelectionFont
Else
FontDialog1.Font = Nothing
End If
FontDialog1.ShowApply = True
If FontDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
rtbDoc.SelectionFont = FontDialog1.Font
End If
End Sub
Figure 10: Font dialog in use Similarly, the font color menu option is used to display a standard color dialog to the user; if the user selects a color from the dialog, the Private Sub FontColorToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles FontColorToolStripMenuItem.Click
ColorDialog1.Color = rtbDoc.ForeColor
If ColorDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
rtbDoc.SelectionColor = ColorDialog1.Color
End If
End Sub
The next three sections of code are the subroutines used to set the selected text’s bold, italic, or underline properties. Each section is set up to work such that, if the selected text is bold, selecting the bold option will remove the bolding (or italics, or underline). (As they all basically work the same, I am only showing bold here.) Private Sub BoldToolStripMenuItem_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles BoldToolStripMenuItem.Click
If Not rtbDoc.SelectionFont Is Nothing Then
Dim currentFont As System.Drawing.Font = rtbDoc.SelectionFont
Dim newFontStyle As System.Drawing.FontStyle
If rtbDoc.SelectionFont.Bold = True Then
newFontStyle = FontStyle.Regular
Else
newFontStyle = FontStyle.Bold
End If
rtbDoc.SelectionFont = New Font(currentFont.FontFamily, _
currentFont.Size, newFontStyle)
End If
End Sub
The “Normal” font menu option returns the selected text to a normal, unadorned format: Private Sub NormalToolStripMenuItem_Click(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles NormalToolStripMenuItem.Click
If Not rtbDoc.SelectionFont Is Nothing Then
Dim currentFont As System.Drawing.Font = rtbDoc.SelectionFont
Dim newFontStyle As System.Drawing.FontStyle
newFontStyle = FontStyle.Regular
rtbDoc.SelectionFont = New Font(currentFont.FontFamily, _
currentFont.Size, newFontStyle)
End If
End Sub
The menu option used to set the page color is used to expose a color dialog box to the user; if the user selects a color form the dialog, the back color of the rich text box control is set to that color. The code to support this function is as follows: Private Sub PageColorToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles PageColorToolStripMenuItem.Click
ColorDialog1.Color = rtbDoc.BackColor
If ColorDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then
rtbDoc.BackColor = ColorDialog1.Color
End If
End Sub
Figure 11: Color dialog in use The undo and redo functions are used to back up or restore changes made to the content of the control during an edit; the rich text box control supports the undo and redo function directly, so all you need to do in order to add undo and redo support is merely evoke the method directly from the control, make the call, test to determine whether or not the control can execute the undo or redo request, and, if it is supported, call the method: Private Sub mnuUndo_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles mnuUndo.Click
If rtbDoc.CanUndo Then rtbDoc.Undo()
End Sub
Private Sub mnuRedo_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles mnuRedo.Click
If rtbDoc.CanRedo Then rtbDoc.Redo()
End Sub
The next three sections of code address setting the document’s horizontal alignment property to support left, centered, or right justification of the selected text. Each of these alignment control options is directly supported by the control: Private Sub LeftToolStripMenuItem_Click_1(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles LeftToolStripMenuItem.Click
rtbDoc.SelectionAlignment = HorizontalAlignment.Left
End Sub
Private Sub CenterToolStripMenuItem_Click_1(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles CenterToolStripMenuItem.Click
rtbDoc.SelectionAlignment = HorizontalAlignment.Center
End Sub
Private Sub RightToolStripMenuItem_Click_1(ByVal sender As _
System.Object, ByVal e As System.EventArgs) _
Handles RightToolStripMenuItem.Click
rtbDoc.SelectionAlignment = HorizontalAlignment.Right
End Sub
Figure 12: Alignment options Adding and removing bullets is also directly supported by the control. The Private Sub AddBulletsToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles AddBulletsToolStripMenuItem.Click
rtbDoc.BulletIndent = 10
rtbDoc.SelectionBullet = True
End Sub
Private Sub RemoveBulletsToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles RemoveBulletsToolStripMenuItem.Click
rtbDoc.SelectionBullet = False
End Sub
Figure 12: Bullet options Setting the indentation level for the selected text is also directly supported by the control: Private Sub mnuIndent0_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles mnuIndent0.Click
rtbDoc.SelectionIndent = 0
End Sub
Figure 13: Indentation options The application contains a separate dialog box used to find a text string within the current document. If the user selects the Find menu option, the application will create and display a new instance of the search form (frmFind.vb): Private Sub FindToolStripMenuItem_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles FindToolStripMenuItem.Click
Dim f As New frmFind()
f.Show()
End Sub
Similarly, if the user selects the Find and Replace menu option, the application will create and display a new instance of the find and replace form (frmReplace.vb): Private Sub FindAndReplaceToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles FindAndReplaceToolStripMenuItem.Click
Dim f As New frmReplace()
f.Show()
End Sub
The print document is set to contain the contents of the current rich text box control. In order to support print preview, page setup, and printing, given the modifications made to the extended rich text box control, all that needs to be done is to pass the print document to each of the related standard dialog boxes: Private Sub PreviewToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles PreviewToolStripMenuItem.Click
PrintPreviewDialog1.Document = PrintDocument1
PrintPreviewDialog1.ShowDialog()
End Sub
Private Sub PrintToolStripMenuItem_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles PrintToolStripMenuItem.Click
PrintDialog1.Document = PrintDocument1
If PrintDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then
PrintDocument1.Print()
End If
End Sub
Private Sub mnuPageSetup_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles mnuPageSetup.Click
PageSetupDialog1.Document = PrintDocument1
PageSetupDialog1.ShowDialog()
End Sub
The next subroutine is a little more interesting; it is used to embed an image file into the extended rich text box document. This subroutine uses an open file dialog box set to filter the extensions used for bitmaps, JPEGs, and GIF files. The user may navigate to the file that they want to embed into the document (placing it at the insertion point defined by the cursor). Private Sub InsertImageToolStripMenuItem_Click(ByVal sender _
As System.Object, ByVal e As System.EventArgs) _
Handles InsertImageToolStripMenuItem.Click
OpenFileDialog1.Title = "RTE - Insert Image File"
OpenFileDialog1.DefaultExt = "rtf"
OpenFileDialog1.Filter = "Bitmap Files|*.bmp|JPEG Files|*.jpg|GIF
Files|*.gif"
OpenFileDialog1.FilterIndex = 1
OpenFileDialog1.ShowDialog()
If OpenFileDialog1.FileName = "" Then Exit Sub
Try
Dim strImagePath As String = OpenFileDialog1.FileName
Dim img As Image
img = Image.FromFile(strImagePath)
Clipboard.SetDataObject(img)
Dim df As DataFormats.Format
df = DataFormats.GetFormat(DataFormats.Bitmap)
If Me.rtbDoc.CanPaste(df) Then
Me.rtbDoc.Paste(df)
End If
Catch ex As Exception
MessageBox.Show("Unable to insert image format selected.", "RTE –
Paste", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Figure 15: Embedding an image file Once the user selects a file through the open file dialog, the subroutine will create an image using the The last section of the main form’s code is contained in the printing region. The calls used to print, due to the use of the extended rich text box control, are very simple: Private Sub PrintDocument1_BeginPrint(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintEventArgs) _
Handles PrintDocument1.BeginPrint
' Adapted from Microsoft's example for extended richtextbox control
'
checkPrint = 0
End Sub
The The Private Sub PrintDocument1_PrintPage(ByVal sender As Object, _
ByVal e As System.Drawing.Printing.PrintPageEventArgs) _
Handles PrintDocument1.PrintPage
' Adapted from Microsoft's example for extended richtextbox control
'
' Print the content of the RichTextBox. Store the last character
printed.
checkPrint = rtbDoc.Print(checkPrint, rtbDoc.TextLength, e)
' Look for more pages
If checkPrint < rtbDoc.TextLength Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
End Sub
Figure 16: Print preview The print section wraps up the rest of the main form class. Code: The Find and Replace FormThe find and replace form is supported with the The Find and Replace form supports four subroutines:
The Find subroutine is pretty straightforward, it will search the entire document for the first occurrence of the search term defined by the user on the form. It will search in one of two ways: with or without matching the case of the search term. Depending upon whether or not the user has checked the Match Case check box on the form, the application will search for the text using either the binary or text compare method. With the binary method, the search term must match exactly (including case); with the text compare method, the strings just need to match. The “ Private Sub btnFind_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnFind.Click
Dim StartPosition As Integer
Dim SearchType As CompareMethod
If chkMatchCase.Checked = True Then
SearchType = CompareMethod.Binary
Else
SearchType = CompareMethod.Text
End If
StartPosition = InStr(1, frmMain.rtbDoc.Text, _
txtSearchTerm.Text, SearchType)
If StartPosition = 0 Then
MessageBox.Show("String: '" & txtSearchTerm.Text.ToString() & _
"' not found", "No Matches", _
MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
Exit Sub
End If
frmMain.rtbDoc.Select(StartPosition - 1, txtSearchTerm.Text.Length)
frmMain.rtbDoc.ScrollToCaret()
frmMain.Focus()
End Sub
The Find Next function works in a manner consistent with the Find function; the only difference is that it sets the start position to the current position of the selection starting point within the document so that the Find Next function will not start at the beginning of the document each time it searches: Private Sub btnFindNext_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnFindNext.Click
Dim StartPosition As Integer = frmMain.rtbDoc.SelectionStart + 2
Dim SearchType As CompareMethod
If chkMatchCase.Checked = True Then
SearchType = CompareMethod.Binary
Else
SearchType = CompareMethod.Text
End If
StartPosition = InStr(StartPosition, frmMain.rtbDoc.Text, _
txtSearchTerm.Text, SearchType)
If StartPosition = 0 Then
MessageBox.Show("String: '" & txtSearchTerm.Text.ToString() & _
"' not found", "No Matches", _
MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
Exit Sub
End If
frmMain.rtbDoc.Select(StartPosition - 1, txtSearchTerm.Text.Length)
frmMain.rtbDoc.ScrollToCaret()
frmMain.Focus()
End Sub
The Replace subroutine is quite simple. It merely tests to see if any text is selected and, if it is, it is replaced with the replacement text entered into the form by the user; it then moves to the next occurrence of the search term if one exists: Private Sub btnReplace_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnReplace.Click
If frmMain.rtbDoc.SelectedText.Length <> 0 Then
frmMain.rtbDoc.SelectedText = txtReplacementText.Text
End If
Dim StartPosition As Integer = frmMain.rtbDoc.SelectionStart + 2
Dim SearchType As CompareMethod
If chkMatchCase.Checked = True Then
SearchType = CompareMethod.Binary
Else
SearchType = CompareMethod.Text
End If
StartPosition = InStr(StartPosition, frmMain.rtbDoc.Text,_
txtSearchTerm.Text, SearchType)
If StartPosition = 0 Then
MessageBox.Show("String: '" & txtSearchTerm.Text.ToString() & _
"' not found", "No Matches", _
MessageBoxButtons.OK, MessageBoxIcon.Asterisk)
Exit Sub
End If
frmMain.rtbDoc.Select(StartPosition - 1, txtSearchTerm.Text.Length)
frmMain.rtbDoc.ScrollToCaret()
frmMain.Focus()
End Sub
The Replace All function is a little different in that it uses the Replace method to replace every instance of the search term with the replacement term throughout the entire body of the text: Private Sub btnReplaceAll_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnReplaceAll.Click
Dim currentPosition As Integer = frmMain.rtbDoc.SelectionStart
Dim currentSelect As Integer = frmMain.rtbDoc.SelectionLength
frmMain.rtbDoc.Rtf = Replace(frmMain.rtbDoc.Rtf, _
Trim(txtSearchTerm.Text), _
Trim(txtReplacementText.Text))
frmMain.rtbDoc.SelectionStart = currentPosition
frmMain.rtbDoc.SelectionLength = currentSelect
frmMain.Focus()
End Sub
Again, the Code: Rich Text Box Print ControlThe code in the class library contained in the SummaryThis article and sample application have attempted to demonstrate some of the available techniques useful in creating and managing text and text files through the use of the
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||