- Visual Basic項目開發案例精粹
- 馮小燕等編著
- 377字
- 2018-12-26 18:43:05
第1章 文本編輯器
文本編輯是計算機最常用的數據處理功能之一。微軟公司推出的Microsoft Word就是一款經典的文本編輯軟件,具有很強的文本編輯和處理能力,在學習和工作中應用極為廣泛。此外,Windows操作系統自帶的記事本也是一個文本編輯軟件,能夠進行簡單的文本處理。本章使用Visual Basic 6.0也可以設計一個文本編輯器。
1.1 需求分析
通常,文本編輯器具有打開、保存、剪切、復制、粘貼等功能,本章設計的文本編輯器包括以下一些基本功能。
(1)能夠同時打開多個不同的編輯窗口,對多個文本進行獨立編輯。這些窗口包含在一個父窗體中,并都具有獨立的編輯功能。
(2)可以打開已經保存在磁盤上的文本文件。將文件中的內容顯示在文本編輯器的某個指定窗體中,同時在該窗體的標題欄和狀態欄上顯示該文件的存放路徑。
(3)可以將文本保存到指定的路徑下。
(4)可以打印任一窗口中的文本。
(5)能夠對文本的字體進行設置,包括字體、大小、字形、刪除線和下畫線效果,以及文本顏色。
(6)可以從同一個文本編輯窗口中剪切、復制和粘貼文本,也能從不同的文本編輯窗口中剪切、復制和粘貼文本。
(7)可以設置文本的對齊方式,包括左對齊、居中對齊和右對齊。
(8)此外,該文本編輯器界面簡潔、操作簡單,具有用戶熟悉的Word軟件的風格。圖1-1為多窗體文本編輯器的界面圖。

圖1-1 多窗體文本編輯器界面
1.2 技術要點
本章將設計一個多窗體文本編輯器,可以同時對多個文本進行編輯操作。多窗體文本編輯主要通過多文檔界面MDI的編程技術實現,其中涉及的技術要點有窗體對象、上下級菜單、指定活動子窗體、設置子窗體和子窗體排列等。
在文本編輯器中,使用RichTextBox控件放置文本。通過RichTextBox控件的SelAlignment屬性可以設置文字的對齊方式,包括左對齊、居中和右對齊。
文本的打開、另存、打印、字體和顏色對話框是通過CommonDialog控件實現的。
使用Clipboard對象實現文本的剪切、復制和粘貼功能。
通過菜單編輯器設計子窗體菜單和父窗體菜單,以及RichTextBox控件上的彈出式編輯菜單。
工具欄和狀態欄分別使用Toolbar和StatusBar控件設計,工具欄按鈕上的圖片通過ImageList控件添加。
1.3 系統結構
創建一個新的工程,添加一個MDI窗體和一個Form窗體。在Form窗體上添加ImageList、Toolbar、StatusBar、CommonDialog和RichTextBox控件。工程的對象及其屬性值如表1-1所示。
表1-1 工程的對象及其屬性值

MDI窗體和Form窗體分別有各自的菜單欄,通過菜單欄中的各項命令,可以實現文本的編輯操作。MDI窗體和Form窗體的菜單欄列表,如表1-2所示。
表1-2 窗體對象中的菜單欄列表

和MDI窗體不同的是,Form窗體還有工具欄,該工具欄中的大部分命令與Form窗體的菜單項命令可以實現相同的編輯操作。表1-3為Form窗體中的工具欄列表。
表1-3 Form窗體中的工具欄列表

工具欄控件Toolbar中索引為5、9、11等按鈕的樣式被設置為3,作為按鈕間的分隔使用。因此,在表1-3中并未將其列出。
此外,工具欄控件Toolbar的按鈕與ImageList控件中的圖像是相對應的,其對應關系如表1-4所示。
表1-4 Toolbar與ImageList控件對應關系

1.4 實現過程
根據設計過程和程序功能,可以將文本編輯器的實現過程分為創建工程、父窗體設計、子窗體設計,以及子窗體中的各菜單項、工具欄和狀態欄的設計。
1.4.1 創建工程
新建一個工程,默認情況下該工程已經包含一個Form窗體,用做文本編輯窗體。
此外,還要向該工程中添加一個MDI Form窗體,用做父窗體。添加MDI Form窗體方法一般有兩種:其一,從“工程”菜單項中選擇“添加MDI窗體”子菜單項即可;其二,單擊工具欄“添加窗體”的下三角按鈕,從下拉列表框中選擇“添加MDI窗體”即可。
Form窗體和MDI Form窗體的屬性設置見表1-1。通常,新建工程后,啟動對象為Form窗體。本章要將MDI Form窗體,即父窗體設置為啟動對象,設置步驟如下所示。
(1)從“工程”菜單項的下拉列表框中,選擇 “工程屬性…”子菜單項,彈出“工程屬性”對話框。
(2)打開“工程屬性”對話框中的“通用”選項卡。
(3)從“啟動對象”下拉列表框中,選擇父窗體即可。圖1-2為“工程屬性”對話框。

圖1-2 “工程屬性”對話框
1.4.2 父窗體設計
父窗體是個容器,主要用于放置文本編輯窗體,圖1-3為父窗體的設計界面。從“工程”菜單項的下拉列表框中,選擇“部件…”子菜單項,在“控件”選項卡列表框中選擇Microsoft Common Dialog Control 6.0 (SP3)選項,將CommonDialog控件添加到控件工具箱中。向窗體上添加一個CommonDialog控件,用做程序中的“打開”對話框。

圖1-3 父窗體的設計界面
父窗體的菜單比較簡單,當所有子窗體都關閉時,可以通過該菜單新建或直接打開一個子窗體。而當父窗體中只要有一個子窗體獲得焦點時,該菜單會被子窗體的菜單取代,父窗體的菜單根據表1-2編輯。
1. 子窗體對象
本章設計的文本編輯器可以在程序運行時創建若干個子窗體,同時可以編輯多個文本,也可以實現子窗體間文本的復制與粘貼操作。子窗體的創建不是通過程序設計時添加多個Form窗體實現的。事實上,本章在設計時只添加了一個Form子窗體,作為文本編輯窗體的原型。通過窗體對象的方法,創建窗體對象的實例,每個實例都繼承對象原型的所有屬性、方法和事件。而且,在應用程序中,這些實例都是獨立于對象原型的。同時,實例之間雖然具有完全相同的屬性、方法和事件,但是,各實例之間的操作卻并不相互影響。
以新建文本編輯窗體為例,創建窗體對象實例的完整程序代碼如程序清單1-1 所示。父窗體加載程序代碼與此類似。
程序清單1-1新建文本
1. Public intSubFormCounts As Integer '聲明創建的子窗體對象實例數量變量 2. 3. Private Sub menuFileNew_Click() '新建文本 4. Dim frmSubForm As Form '聲明Form類型的窗體對象變量 5. 6. Set frmSubForm=New frmTextEdit '給變量frmSubForm賦值 7. frmSubForm.Show '顯示子窗體對象實例 8. intSubFormCounts=intSubFormCounts+1 '更新子窗體數量 9. frmSubForm.Caption="文本"&Str(mdfMainForm.intSubFormCounts) 10. End Sub
程序說明:本段代碼主要是使用面向對象的方法,創建窗體對象實例,實現新建文本功能。在父窗體加載、執行新建和打開命令時,程序都聲明和創建子窗體對象實例。第1行代碼是在父窗體的通用代碼區聲明intSubFormCounts變量,每次創建新的子窗體對象實例時,都累計子窗體對象實例的數量。第4行聲明frmSubForm為Form類型的窗體對象變量。窗體對象變量的聲明與其他類型變量的聲明方法是一樣的,可以使用Dim、Public和Provate等關鍵字聲明。聲明了窗體對象變量之后,第6行就使用Set語句和New關鍵字創建窗體對象實例。第7 行通過Show方法將剛創建窗體對象實例顯示出來。同時,更新intSubFormCounts變量來累積子窗體對象實例的數量。
2. 打開文本
打開文本的程序主要包括三大部分,分別是設置和顯示“打開”對話框、創建子窗體對象實例和加載文件。打開文本的程序代碼如程序清單1-2所示。
程序清單1-2打開文本
1. Private Sub menuFileOpen_Click() '打開文本 2. On Error GoTo ErrorTrap 3. 4. '-----------------------“打開”對話框設置----------------------------------------- 5. cdlDialog.CancelError=True '設置“取消”為True 6. cdlDialog.Flags=cdlOFNHideReadOnly '隱藏“打開”對話框上的只讀復選框 7. cdlDialog.Filter="Text Files"&"(*.txt)|*.txt" '設置文件過濾器 8. cdlDialog.FilterIndex=1 '設置默認過濾器 9. cdlDialog.ShowOpen '顯示“打開”對話框 10. 11. '-----------------------調用新建文本程序來創建子窗體對象實例--------------- 12. menuFileNew_Click 13. 14. '-----------------------向子窗體文本編輯區加載文本------------------------------ 15. mdfMainForm.ActiveForm.rtbRichText.LoadFile cdlDialog.FileName,1 '加載文件 16. mdfMainForm.ActiveForm.Caption="文本 "&cdlDialog.FileName '窗體標題 17. '欄上顯示打開的文件名 18. sbrStatus.Panels(2).Text=cdlDialog.FileName '將文件路徑顯示在狀態欄上 19. 20. Exit Sub 21. ErrorTrap: 22. End Sub
程序說明:第5~9行是將CommonDialog控件設置為“打開”對話框。第12行通過調用了新建文本過程,創建子窗體對象實例,簡化了程序編寫。第15行和第16行中的ActiveForm屬性用于返回父窗體中獲得焦點的子窗體,即向正在活動的子窗體中加載文本。
1.4.3 子窗體設計
子窗體是進行文本編輯的主要窗體,其菜單和工具欄包含了文本編輯的所有命令。圖1-4為子窗體的設計界面。

圖1-4 子窗體的設計界面
從“部件”對話框中選擇Microsoft Rich Textbox Control 6.0 (SP4) 和Microsoft Windows Common Control 6.0 (SP6)選項,將RichTextBox控件添加到控件工具箱中。向子窗體上添加相應控件,并根據表1-1、表1-2和表1-3分別設置控件屬性、編輯菜單和設計工具欄。
1.4.4 用戶區尺寸設置
RichTextBox控件是文本存放和編輯的容器,即用戶區。其位置和大小應充滿子窗體,但又不能遮掩工具欄和狀態欄等。在程序運行時,用戶隨時都可能改變子窗體的大小,因此設置用戶區的尺寸和位置狀態非常必要。用戶區的設置分為程序加載時的初始化設置和用戶改變窗體大小時的自動設置。
當改變窗體大小時,通過子窗體的Resize過程,改變用戶區的位置和大小,使之隨窗體大小一起改變,程序代碼如程序清單1-3 所示。程序加載時,用戶區的初始化程序代碼與此相同。
程序清單1-3用戶區尺寸設置
1. Private Sub Form_Resize() 2. On Error GoTo ErrorTrap 3. 4. With mdfMainForm.ActiveForm 5. sbrStatus.Top=frmTextEdit.ScaleHeight-tbrToolbar.Height-sbrStatus.Height 6. 7. .rtbRichText.Left=.ScaleLeft 8. .rtbRichText.Top=.tbrToolbar.Top+.tbrToolbar.Height 9. .rtbRichText.Height=.sbrStatus.Top-.rtbRichText.Top 10. .rtbRichText.Width=.ScaleWidth 11. End With 12. ErrorTrap: 13. End Sub
程序說明:本段代碼主要用于實現當窗體大小變化時,自動改變RichTextBox控件的大小,使之隨窗體大小一起改變。第1行窗體的Resize事件在窗體尺寸調整時被調用,第5行用于確定狀態欄的位置,避免狀態欄被RichTextBox控件覆蓋。第7~10 行即RichTextBox控件的大小隨窗體尺寸的變化而做相應調整。
1.4.5 文件菜單設計
“文件”菜單項主要用于實現新建、打開、另存和打印等功能,新建、打開功能的程序代碼與父窗體中的基本相同。
1. 另存文本
另存文本的程序主要包括兩大部分,分別是設置和顯示“另存為”對話框和保存文件,程序代碼如程序清單1-4所示。
程序清單1-4另存文本
1. Private Sub menuFileSaveAs_Click() '另存文本 2. On Error GoTo ErrorTrap 3. 4. '-----------------------“另存為”對話框設置--------------------------
5. cdlDialog.CancelError=True '設置“取消”為True 6. cdlDialog.Flags=cdlOFNHideReadOnly'隱藏“打印”對話框上的只讀復選框 7. cdlDialog.Filter="Text Files"&"(*.txt)|*.txt" '設置文件過濾器 8. cdlDialog.FilterIndex=1 '設置默認過濾器 9. cdlDialog.Action=2 '顯示“另存為”對話框 10. 11. '-----------------------保存文件-------------------------------------------- 12. If rtbRichText.Text<>""Then 13. rtbRichText.SaveFile cdlDialog.FileName,1 14. End If 15. 16. Exit Sub 17. ErrorTrap: 18. End Sub
程序說明:第5~9行是將CommonDialog控件設置為“另存為”對話框,第12~14行將文本編輯窗口中的文本保存到指定的路徑下。
2. 打印文本
打印文本的程序主要包括兩大部分,分別是設置和顯示“打印”對話框和打印文件,程序代碼如程序清單1-5所示。
程序清單1-5打印文本
1. Private Sub menuFilePrint_Click() '打印文本 2. On Error GoTo ErrorTrap 3. Dim intCopies As Integer '聲明打印頁數變量 4. 5. '-----------------------“打印”對話框設置-------------------------- 6. cdlDialog.CancelError=True '設置“取消”為True 7. cdlDialog.Flags=cdlPDAllPages '設置全部頁選項按鈕狀態 8. cdlDialog.Action=5 '顯示“打印”對話框 9. intCopies=cdlDialog.Copies '對打印頁數變量賦值 10. o 11. '-----------------------打印文本----------------------------------------- 12. Printer.Print 13. rtbRichText.SelPrint Printer.Hdc '打印用戶區內容 14. Printer.EndDoc '打印結束 15. 16. Exit Sub 17. ErrorTrap: 18. End Sub
程序說明:第6~9行是將CommonDialog控件設置為“打印”對話框,第12~14行將文本編輯窗口中的文本打印出來。
1.4.6 編輯菜單設計
“編輯”菜單項包含剪切、復制、粘貼和查找功能,文本的剪切、復制和粘貼是通過剪貼板Clipboard對象實現的。
1. 復制文本
以復制文本為例,通過RichTextBox控件的SelText屬性返回被反白選中的文本,然后使用Clipboard對象的SetText方法將SelText屬性返回的文本寫入到Clipboard中。復制文本的程序代碼如程序清單1-6所示。
程序清單1-6復制文本
1. Private Sub menuEditCopy_Click() '復制 2. If rtbRichText.SelText<>""Then '如果選中了文本就復制 3. Clipboard.SetText rtbRichText.SelRTF,vbCFRTF '將文本復制到剪貼板上 4. End If 5. End Sub
程序說明:第2 行使用RichTextBox控件的SelText屬性判斷是否有文本被選中,第3行將文本復制到剪貼板上。
剪切文本的程序代碼與此類似。所不同的是,用SetText方法將被選中的文本寫入到Clipboard后,設置SelText屬性值為空即可。
2. 粘貼文本
Clipboard對象的GetText方法可以從Clipboard中取得文本數據,RichTextBox控件的SelRTF屬性可用于設置當前選擇的文本。將GetText方法取得的文本數據賦給SelRTF屬性,即可將被選中的文本替換為Clipboard中的數據,即實現粘貼功能。粘貼文本的程序代碼如程序清單1-7所示。
程序清單1-7粘貼文本
1. Private Sub menuEditPaste_Click() '粘貼 2. rtbRichText.SelRTF=Clipboard.GetText(vbCFRTF) 3. End Sub
程序說明:第2行即通過RichTextBox控件的SelRTF屬性將剪貼板上的文本粘貼到文本中。
如果用戶當前沒有選擇任何文本,那么上述粘貼文本的程序將向光標位置插入Clipboard中的數據。
細心的讀者也許會想到,本章設計的文本編輯器是否可以通過快捷鍵Ctrl+C、Ctrl+X和Ctrl+V來分別實現復制、剪切和粘貼功能,答案是肯定的。在表1-2中,并沒有對這三個操作設置快捷鍵。因為RichTextBox控件可以直接響應上述三個快捷鍵操作,如果在菜單設計的時候設置了相同的快捷鍵,那么程序會響應兩次,從而相同的文本可能會被粘貼兩次。
3. 查找文本
查找是使用RichTextBox控件的Find方法實現的。設計思路是通過InputBox函數返回用戶輸入的欲查找的文字,再將該文字作為Find方法的參數,從指定的位置開始查找其所在的位置。查找文本的程序代碼如程序清單1-8所示。
程序清單1-8查找文本
1. Private Sub menuEditFind_Click() '查找文本 2. Dim strFindString As String 3. 4. strFindString=InputBox("輸入要查找的字符","查找",rtbRichText.SelText) 5. rtbRichText.SelStart=0 6. rtbRichText.Find strFindString,,Len(rtbRichText.TextRTF) 7. End Sub
程序說明:第4行使用InputBox函數輸入要查找的文本。第5行設置從什么位置開始查找,本段代碼是從頭開始查找。第6行返回查找到的文本。
在很多文本編輯軟件中,都可以通過彈出式菜單進行編輯操作。本章也對作為用戶區的RichTextBox控件設計了彈出式編輯菜單。在RichTextBox控件的MouseDown事件中使用PopupMenu方法即可實現。
1.4.7 格式菜單設計
“格式”菜單項包含字體和顏色設置功能,字體和顏色設置都是通過CommonDialog控件實現的。
文字的粗體、傾斜和下畫線屬性需要同時反映在“字體”對話框和工具欄相關按鈕上。打開“字體”對話框時,需要將當前文字字體屬性值賦給CommonDialog控件的相應屬性,使得對話框打開后顯示當前文字的狀態。給CommonDialog控件屬性賦值程序代碼如程序清單1-9所示。
程序清單1-9字體
1. Private Sub menuFormatFont_Click() '設置文本字體 2. On Error GoTo ErrorTrap 3. 4. '-----------------------“字體”對話框設置---------------------------------------- 5. cdlDialog.CancelError=True '設置“取消”為True 6. cdlDialog.Flags=cdlCFEffects Or cdlCFBoth '設置對話框具有下畫線和顏色效果等 7. 8. '將RichTextBox控件中文本屬性賦給CommonDialog控件 9. '如果當前選擇了文本,將文本的字體屬性賦給CommonDialog控件 10. If rtbRichText.SelText<>""Then 11. cdlDialog.FontName=rtbRichText.SelFontName 12. cdlDialog.FontSize=rtbRichText.SelFontSize 13. cdlDialog.FontBold=rtbRichText.SelBold 14. cdlDialog.FontItalic=rtbRichText.SelItalic 15. cdlDialog.FontUnderline=rtbRichText.SelUnderline 16. cdlDialog.FontStrikethru=rtbRichText.SelStrikeThru 17. 18. '如果當前沒有選中任何文本,將光標處的字體屬性賦給CommonDialog控件 19. Else 20. cdlDialog.FontName=rtbRichText.Font.Name 21. cdlDialog.FontSize=rtbRichText.Font.Size 22. cdlDialog.FontBold=rtbRichText.Font.Bold 23. cdlDialog.FontItalic=rtbRichText.Font.Italic
24. cdlDialog.FontUnderline=rtbRichText.Font.Underline 25. cdlDialog.FontStrikethru=rtbRichText.Font.Strikethrough 26. End If 27. 28. cdlDialog.Action=4 '顯示“字體”對話框 29. 30. '-----------------------設置RichTextBox控件中字體---------------------------- 31. '如果當前選擇了文本,更新文本字體 32. If rtbRichText.SelText<>""Then 33. rtbRichText.SelFontName=cdlDialog.FontName 34. rtbRichText.SelFontSize=cdlDialog.FontSize 35. rtbRichText.SelBold=cdlDialog.FontBold 36. rtbRichText.SelItalic=cdlDialog.FontItalic 37. rtbRichText.SelUnderline=cdlDialog.FontUnderline 38. rtbRichText.SelStrikeThru=cdlDialog.FontStrikethru 39. 40. '如果當前沒有選中任何文本,更新光標處的字體屬性 41. Else 42. rtbRichText.Font.Name=cdlDialog.FontName 43. rtbRichText.Font.Size=cdlDialog.FontSize 44. rtbRichText.Font.Bold=cdlDialog.FontBold 45. rtbRichText.Font.Italic=cdlDialog.FontItalic 46. rtbRichText.Font.Underline=cdlDialog.FontUnderline 47. rtbRichText.Font.Strikethrough=cdlDialog.FontStrikethru 48. End If 49. 50. '-----------設置工具欄上的三個字體風格按鈕的狀態,彈起或按下---------- 51. '設置工具欄上的粗體按鈕風格 52. If rtbRichText.SelBold=True Then 53. tbrToolbar.Buttons.Item(14).Value=tbrPressed 54. blnBold=True 55. Else 56. tbrToolbar.Buttons.Item(14).Value=tbrUnpressed 57. blnBold=False 58. End If 59. 60. '設置工具欄上的斜體按鈕風格 61. If rtbRichText.SelItalic=True Then 62. tbrToolbar.Buttons.Item(15).Value=tbrPressed 63. blnItalic=True 64. Else 65. tbrToolbar.Buttons.Item(15).Value=tbrUnpressed 66. blnItalic=False 67. End If 68. 69. '設置工具欄上的下畫線按鈕風格 70. If rtbRichText.SelUnderline=True Then 71. tbrToolbar.Buttons.Item(16).Value=tbrPressed 72. blnUnderline=True 73. Else 74. tbrToolbar.Buttons.Item(16).Value=tbrUnpressed 75. blnUnderline=False 76. End If
77. 78. Exit Sub 79. ErrorTrap: 80. End Sub
程序說明:在設置字體屬性時,用戶可能選擇了部分文字,此時要將該文字字體屬性賦給CommonDialog控件;用戶也可能沒選擇任何文字,此時要將光標處的字體屬性賦給CommonDialog控件。第10~26行就是將選中文本或光標處的字體屬性賦給CommonDialog控件,第32~48行是設置用戶區文本字體程序,其功能正好與設置CommonDialog屬性相反,第50~76行主要是在設置了字體屬性后,更新工具欄上按鈕的狀態,彈起或按下。
顏色設置比較簡單,只要將CommonDialog控件的Color屬性賦給RichTextBox控件的SelColor屬性即可。
1.4.8 窗口菜單設計
“窗口”菜單項主要用于設置子窗體在父窗體中的排列方式,有層疊排列、水平平鋪、垂直平鋪和重排圖標四種。程序代碼如程序清單1-10所示。
程序清單1-10子窗體排列
1. Private Sub menuCascade_Click() 2. mdfMainForm.Arrange vbCascade 3. End Sub 4. 5. Private Sub menuTileHorizontal_Click() 6. mdfMainForm.Arrange vbTileHorizontal 7. End Sub 8. 9. Private Sub menuTileVertical_Click() 10. mdfMainForm.Arrange vbTileVertical 11. End Sub 12. 13. Private Sub menuArrangeIcons_Click() 14. mdfMainForm.Arrange vbArrangeIcons 15. End Sub
程序說明:第2行是層疊排列所有非最小化的子窗體,第6行是水平平鋪所有非最小化的子窗體,第10行是垂直平鋪所有非最小化的子窗體,第14行是重排最小化子窗體的圖標。
1.4.9 工具欄和狀態欄設計
工具欄的大部分功能與菜單欄相同。在工具欄按鈕的Click事件中調用相應的菜單項Click事件即可,而不需要單獨編寫響應程序。
文本的對齊方式可以通過設置RichTextBox控件的SelAlignment屬性值實現。SelAlignment設置為0、1和2時,文本分別左對齊、右對齊和居中對齊。設置文本對齊時,選中的文本行或光標所在的行會執行相應的動作。
狀態欄主要用于顯示大寫、被打開文件的保存路徑和系統時間等,通過設置StatusBar控件的屬性即可實現。