21. TextBox控制項與RichTextBox控制項

RichTextBox控制項是Visual Basic最具威力的工具之一,你只要稍微修改其屬性設定,它就可以成為像「記事本」一樣的編輯器。本章的重點即在介紹如何建立一個文字編輯器以及介紹一些有關文字方塊控制項(TextBox Control)和RichTextBox控制項的程式設計技巧。

如何利用文字方塊或RichTextBox顯示檔案的內容?
 

文字方塊或是RichTextBox,都可以作為顯示檔案內容的工具。如果要選用文字方塊作為顯示檔案內容的工具,必須把屬性MultiLine設為True,屬性Scrollbars設為"3 - 兩者皆有",才能使視窗具備捲動的功能。

以下這個範例將會載入AUTOEXEC.BAT檔,並利用一個RichTextBox將檔案的內容顯示在一個可捲動的視窗中︰

Option Explicit

Private Sub Form_Load()
    Dim strF As String
    `Load a file into a string
    Open "C:\AUTOEXEC.BAT" For Binary As #1
    strF = Space$(LOF(1))
    Get #1, , strF
    Close #1
    `Display file in rich text box
    rtfTest.Text = strF
End Sub

圖21-1顯示了程式執行的結果。


 

 圖21-1 以一個RichTextBox控制項顯示AUTOEXEC.BAT的內容

在這個例子裡,整個AUTOEXEC.BAT檔的內容以二進位檔案模式被讀入到字串變數裡,等待稍後的處理。採用二進位檔案模式是一個十分有用的技巧,因為不管檔案的內容是什麼,二進位檔案模式會將每一個位元組原封不動地從檔案中讀出,這表示,如果這個檔案有一行以上的資料,那麼每一個換行字元(line feed)和機架返回字元(carriage return)都會包含在字串中。( 第十五章"檔案" 對二進位檔案模式的輸出輸入有更詳盡的討論)。

另外,如果讀入的檔案是RTF格式的檔案,你應該把字串指定給RichTextBox控制項的TextRTF屬性,而不是定給Text屬性,這樣,檔案中的格式控制碼就可以被正確的解釋,而顯示出正確的內容。如果不用二進位檔模式讀取檔案的資料,我們有另一種方式可以建立一個含多行資料的字串;你可以把每一個字串串接在一起,在字串與字串之間插入機架返回和換行控制碼,以下這個範例即是利用這種技巧。

Option Explicit

Private Sub Form_Load()
    Dim strA As String, strF As String
    `Load a file into a string
    Open "C:\AUTOEXEC.BAT" For Input As #1
    Do Until EOF(1)
        Line Input #1, strA
        strF = strF & strA & vbCrLf
    Loop
    Close #1
    `Display file in rich text box
    rtfTest.Text = strF
End Sub

這個範例與上個範例有幾點不同:第一,檔案開啟模式不是二進位檔案模式; 第二,程式中使用一個迴圈一次讀取一行資料,串接成一個字串,而非一次將資料全部讀入。


注意:

在Visual Basic 4以前,你必須自行建立機架返回和換行字元,現在Visual Basic已經提供了內建的常數vbCrLf,你可以在範例中看到。


最後附帶提醒一點,文字方塊控制項所能容納的字元數目大約是64000,較小的檔案如AUTOEXEC.BAT可以用文字方塊控制項來顯示,但筆者建議你用RichTextBox控制項,因為這個控制項使用起來較具彈性。


參考資料:

請參閱本章介紹的 "如何將大於64KB的文字放進文字方塊中?" 


如何建立一個簡單的文字編輯器?
 

如果需要在你的應用程式中加上一個全功能的文字處理器視窗,請考慮使用OLE將一個Microsoft Word物件內嵌在你的程式中; 但如果你需要的只是像WordPad或「記事本」之類簡單的編輯器,那麼TextBox或RichTextBox控制項就應足敷所需了。讓我們用以下這個範例來介紹如何建立一個簡單的文字編輯器。

Option Explicit

Private Sub cmdCut_Click()
    `Cut selected text to clipboard
    Dim strWork As String
    Dim Wstart, Wlength
    `Keep focus on rich text box
    rtfEdit.SetFocus
    `Get working parameters
    strWork = rtfEdit.Text
    Wstart = rtfEdit.SelStart
    Wlength = rtfEdit.SelLength
    `Copy cut text to clipboard
    Clipboard.SetText Mid$(strWork, Wstart + 1, Wlength)
    `Cut out text
    strWork = Left$(strWork, Wstart) + _
        Mid$(strWork, Wstart + Wlength + 1)
    rtfEdit.Text = strWork
    `Position edit cursor
    rtfEdit.SelStart = Wstart
End Sub

Private Sub cmdCopy_Click()
    `Keep focus on edit box
    rtfEdit.SetFocus
    `Copy selected text to clipboard
    Clipboard.SetText rtfEdit.SelText
End Sub

Private Sub cmdPaste_Click()
    `Paste text from clipboard
    Dim strWork As String, strClip As String
    Dim Wstart, Wlength
    `Keep focus on rich text box
    rtfEdit.SetFocus
    `Get working parameters
    strWork = rtfEdit.Text
    Wstart = rtfEdit.SelStart
    Wlength = rtfEdit.SelLength
    `Cut out text, if any, and insert clipboard text
    strClip = Clipboard.GetText()
    strWork = Left$(strWork, Wstart) + strClip + _
        Mid$(strWork, Wstart + Wlength + 1)
    rtfEdit.Text = strWork
    `Position edit cursor
    rtfEdit.SelStart = Wstart + Len(strClip)
End Sub

圖21-2所顯示的是這個文字編輯器執行的情形。


 

 圖21-2 以RichTextBox控制項建立的文字編輯器

在本例中,我們使用了一個RichTextBox控制項rtfEdit。首先設定RightMargin屬性值,以便使裡面的文字可以自動折行; 你可以在Form_Load事件程序中加入以下這一行程式碼,這樣,當使用者打字打到方塊邊緣時就會自動折行:

rtfEdit.RightMargin = rtfEdit.Width

接著,設定ScrallBar屬性為"2 - rtfVertical",使方塊可以垂直捲動。

表單上另外還有三個指令按鈕:cmdCut、cmdCopy和cmdPaste。你可以不用這三個指令按鈕因為在控制項裡就具備了剪下、複製和貼上的功能。程式中的這三個指令按鈕除了模仿這些動作之外,並且也增加了應用程式設計時的彈性。例如,你可能在表單上設計了一個「編輯」功能在主功能表中,這時候就可以把這些程式碼複製到功能表事件程序中,讓表單具有功能表導向的文字編輯功能。

32位元的RichTextBox控制項可接受較大量的資料輸入,支援OLE拖放功能,也支援格式化的本文,另外,RichTextBox控制項更支援了多重字型以及其他許多內嵌的RTF指令(請參閱線上說明)。可以說文字方塊控制項可以做的,它都可以做得更好。

RichTextBox控制項的確比一般的文字方塊制項在功能上強了許多,這樣有誰還會想使用一般文字方塊控制項呢?在32位元軟體的世界裡,文字方塊控制項主要是用來提供簡單的資料輸入功能,但在16位元軟體的世界裡,它卻是唯一的選擇──你必須用它來接收輸入的資料以及顯示檔案的內容。


參考資料:

 第三十二章"資料庫" 中的Jot應用程式也使用了RichTextBox作為文字編輯器。


如何偵測被更動的本文?
 

Change事件是屬於文字方塊控制項和RichTextBox控制項的事件,但使用這個事件來判斷控制項中的本文是否被更動,會有一點小問題需要克服。當控制項所屬的表單被載入時,因預設的本文或初次設定的文字(在設計階段)會被載入控制項中的Text屬性中,因此即使本文未被更動,但是這個載入動作仍會驅動Change事件,這並不是我們所期待的"更動"。

以下這段程式利用兩個Boolean旗標解決了這個問題。在Change事件第一次被驅動時,blnNotFirstFlag變數被設成了True,到了第二次Change事件發生後,blnTextChangeFlag會變成True,這才是使用者第一次真正更動了控制項中本文的時候。由於blnTextChangeFlag變數的範圍涵蓋整個表單,因此,在Form_Unload事件程序中我們才能檢查這個變數的值。當使用者改變了控制項的本文時(blnTextChangeFlag的值為True)表單載出的動作就被中止了。

Option Explicit

Private blnTextChangeFlag As Boolean

Private Sub Form_Load()
    rtfEdit.Text = "Edit this stringDear John, How Do I... "
    blnTextChangeFlag = False
End Sub
Private Sub Form_Unload(Cancel As Integer)
    If blnTextChangeFlag = True Then
        Cancel = True



        MsgBox "Save changes first", 0, _
            "(Testing the Change eventDear John, How Do I... )"
    End If
End Sub

Private Sub rtfEdit_Change()
    Static blnNotFirstFlag As Boolean
    blnTextChangeFlag = blnNotFirstFlag
    blnNotFirstFlag = True
 End Sub

如果要測試這個程式,請在表單中加入一個RichTextbox控制項,取名為rtfEdit。在程式執行時,更改方塊中的文字,然後嘗試關掉表單,看看程式有何反應。

如何將大於64KB的文字資料放進文字方塊控制項中?
 

在16位元的Visual Basic 4應用程式中,文字方塊控制項所能容納的資料量被限制在64KB以下(事實上,依照字串空間的使用情形,資料量上限可能只有32KB)。你可以把文字資料存放在陣列中,然後指定陣列中的元素給文字方塊控制項的Text屬性,這樣就能夠解決資料量限制的問題。在這種方法裡,陣列中個別元素的資料量限制是64KB,但由於陣列的長度可以很長,因此大量的資料仍然可以存放在陣列中,然後以文字方塊控制項顯示。

在以下的範例中,你所看到的文字方塊控制項雖然只能容納幾行文字,但事實上資料的來源卻是一個很大的動態字串陣列,其總資料量可以遠超過64KB。

圖21-3所顯示的是一個大約66800位元組的文字檔以文字方塊控制項顯示的情形。


 

 圖21-3 以文字方塊控制項顯示一個資料量超過64KB的文字檔

要讓本範例能夠執行,請在一張新表單上加入一個文字方塊控制項txtTest和垂直捲軸控制項vsbTest。設定文字方塊的Multiline屬性為True,並設定其ScrollBar屬性為"1-水平捲軸"。垂直捲軸vsbTest用來取代文字方塊控制項內建的垂直捲軸,因此要把它移到文字方塊的右緣。最後,把程式碼加到表單中,把Open陳述式所開啟的檔案改為一個在磁碟中的檔案。

Option Explicit

Private Const LINES = 15
Private strA() As String

Private Sub Form_Load()
    Dim intN 
    `Load dynamic string array from large text file
    Open "C:\WIN32API.TXT" For Input As #1 Len = 1024
    Do Until EOF(1)
        intN = intN + 1
        ReDim Preserve strA(intN + LINES)
        Line Input #1, strA(intN)
    Loop
    Close #1
    `Set scrollbar properties
    With vsbTest
        .Min = 1
        .Max = intN
        .SmallChange = 1
        .LargeChange = intN \ 10
    End With
End Sub

Private Sub vsbTest_Change()
Dim intI As Integer
Dim strTmp As String
    `Create display string from array elements
    For intI = vsbTest.Value To vsbTest.Value + LINES
        strTmp = strTmp + strA(intI) + vbCrLf
    Next intI
    txtTest.Text = strTmp
End Sub

當表單載入時,整個文字檔被讀進了一個動態的字串陣列中,這個動作可能會花上幾秒鐘,因此在真正的應用程式裡,我們建議在載入檔案時同步進行其他的動作,避免使用者感到不耐煩。

一旦檔案載入了記憶體之後,字串陣列的維度就被用來設定垂直捲軸的屬性,而文字方塊的內容會跟隨著垂直捲軸值的改變而更新。在vsbTest_ Change事件程序中,我們把陣列中的文字一行一行地串接在一起,行與行之間用vbCrLf常數連接著。串接在一起的暫時字串,其內容就被指定給文字方塊控制項的Text屬性。

本範例只顯示檔案的內容,並不對使用者更動的文字作任何處理,如果要把這個範例變成一個文字編輯器,必須加上程式碼來更新變動後的字串陣列,才能讓使用者更動文字方塊中的內容。

如何讓使用者在文字方塊或RichTextBox中選用字型?
 

要讓使用者選擇字型,選用對話方塊控制項(CommonDialog Control)是最方便的工具。(它也可以讓使用者選擇檔案、顏色以及設定印表機等等)。要使用這個技巧,首先在表單中加入一個文字方塊控制項txtTest,一個指令按鈕控制項cmdFont和一個選用對話方塊dlgFonts,然後在表單中加入這段程式:

Option Explicit

Private Sub cmdFont_Click()
    dlgFonts.Flags = cdlCFScreenFonts
    dlgFonts.ShowFont
    With txtTest.Font
        .Name = dlgFonts.FontName
        .Bold = dlgFonts.FontBold
        .Italic = dlgFonts.FontItalic
        .Size = dlgFonts.FontSize
    End With
End Sub

Private Sub Form_Load()
    txtTest.Text = "ABCDEF abcdef 0123456789"
End Sub

Form_Load事件程序只是簡單地把樣本文字載入到文字方塊中,真正負責更改字型的是cmdFont_Click事件程序。我們首先設定選用對話方塊的Flag屬性,使得程式能顯示系統的螢幕字型(請參閱線上說明中其他的Flag值),然後用ShowFont方法叫出對話方塊,再根據使用者在選用對話方塊中的選項來設定文字方塊的字型屬性。

圖21-14和21-5顯示的是字型改變前和改變後的情形,圖21-6即是字型選擇對話方塊。


 

 圖21-4 以預設的字型顯示文字方塊中的本文


 

 圖21-5 以使用者選定的字型顯示文字方塊中的本文


 

 圖21-6 「字型」對話方塊