32.資料庫

自從Visual Basic成了一個威力強大的資料庫前端工具之後,Visual Basic在企業環境中所扮演的角色就變得愈來愈重要。本章提供了三個應用程式── AreaCode、DataDump以及Jot ──來介紹Visual Basic如何與Microsoft Access以及其他的資料庫共同運作。

AreaCode應用程式
 

AreaCode應用程式包含了兩張表單,AREACODE.FRM和通用的ABOUT.FRM。AREACODE.FRM使用兩個資料控制項(Data Control)以不同的方式存取同一個電話區域號碼資料庫。第一個資料控制項(在表單上半部)存取資料庫AREACODE.MDB中的一張區域號碼資料表(Table),AREACODE.MDB是由Microsoft Access 97建立的資料庫檔。在AREACODE.FRM下方的資料控制項存取同一個資料庫檔案中的查詢(Query)。AREACODE.MDB資料庫中的資料表以區域號碼為依據,按遞增方式排列(從201到970);而資料庫中的查詢則依美國各州州名縮寫為依據,按照遞增方式排列(由AK到WY)。

因為資料控制項和文字方塊控制項都包含了可簡化資料庫連結動作的屬性,所以AreaCode應用程式只用了幾行與資料庫相關的程式碼。在建立這張表單時,我們只在表單上放了幾個控制項,設定一些屬性,然後再加入幾行程式碼,這樣就大功告成了。

讓資料庫與表單連結有兩個主要步驟:第一步,設定資料控制項的DatabaseName屬性,使資料控制項與資料庫連結在一起;第二步,設定資料控制項的RecordSource屬性,連結資料控制項與資料庫中某個特定的資料表或查詢。一般而言,每個控制項只連結一個資料表或查詢。

當資料控制項與資料庫的連結工作完成之後,其他的控制項(如標籤和下拉式清單方塊)便可以用它們的資料庫相關屬性,透過資料控制項連到資料庫。在本範例中,我們把表單上文字方塊控制項的DataSource屬性設為資料控制項的名稱,然後把DataField屬性設為資料表或查詢中的資料欄名,這樣就完成了整個應用程式與資料庫連結的工作。

雖然使用者可以用資料控制項上面的按鈕來巡覽資料錄,但我們仍然以程式碼提供了另一種處理資料錄的方法。在表單的上半部,文字方塊控制項txtAreaCode讓使用者可以輸入三位數的區域號碼;使用者輸入完區域號碼之後,txtAreaCode_Change事件程序就會被執行。txtAreaCode_Change事件程序首先記錄目前表單上資料錄的書籤(Bookmark),然後開始搜尋使用者指定的記錄。如果搜尋不成功,表單便依記錄的書籤叫回原來的資料錄。

以類似的方式,當使用者在表單下半部的txtStateAbbrev1文字方塊輸入州名縮寫後,程式便會搜尋第一筆符合條件的資料錄。當使用者看到第一筆資料錄後,他可以用資料控制項的"下筆資料錄"按鈕來找尋該州其他的區域號碼。

從圖32-1中你可以看到我們用區域號碼303找到了一筆資料錄,而在表單下半部,我們用州名縮寫WA也成功地找到了資料錄。請注意,表單的上半部與下半部雖然存取同一個資料庫,但它們的搜尋工作是各自獨立的。


 

 圖32-1 用區域號碼303以及州名縮寫WA搜尋資料錄的結果

AREACODE.FRM
 

AreaCode表單包含了兩組幾乎相同的控制項:一組在表單上半部,一組在下半部。表單中兩個資料控制項連結到同一個資料庫,而其他的控制項都透過相關的資料控制項與資料欄連結。為了把所有的控制項組織起來,我們把控制項分組,然後放在兩個框架控制項中。另外,我們在表單上放置了一個通用對話方塊控制項,利用它的ShowHelp方法呼叫相關的說明檔。

我們在Form_Load事件程序中,把資料庫檔案名稱指定給資料控制項的DatabaseName屬性,而且我們用App.Path屬性指明資料庫所在的位置。如果你的資料庫所在的目錄不同於範例應用程式所在的目錄,請將完整的路徑指定給DatabaseName屬性。

圖32-2顯示的是設計階段中的AreaCode表單。


 

 圖32-2 設計階段中的AreaCode表單

請按照以下幾張表和後面的程式碼來建立AreaCode應用程式。

AREACODE.FRM功能表項目
標題 名稱 內縮 啟用
&File mnuFile 0 True
&New mnuNew 1 False
&Open... mnuOpen 1 False
&Save mnuSave 1 False
Save&As... mnuSaveAs 1 False
- mnuFileDash1 1 True
E&xit mnuExit 1 True
&Help mnuHelp 0 True
&Contents mnuContents 1 True
&Search for Help on... mnuSearch 1 True
- mnuHelpDash1 1 True
&About... mnuAbout 1 True
AREACODE.FRM物件與屬性設定
編號 *  屬性
 Form  Name

Caption

BorderStyle

frmAreaCode

Area Codes

3 - Fixed Dialog

 CommonDialog 

1

Name cdlOne
 Frame 

2

Name

Caption

ForeColor

fraByAreaCode

By Area Code

&H000000FF&

 Label 

3

Name

Caption

ForeColor

lblPrompt2

Enter an area code:

&H00FF0000&

 Label 

4

Name

Caption

lblAreaCode2

Area code:

 Label 

5

Name

aption

lblState2

C State:

 Label 

6

Name

Caption

lblStateName2

State name:

 Label 

7

Name

Caption

lblCities2

Cities:

 TextBox 

8

Name

Alignment

txtAreaCode

2 - Center

 TextBox 

9

Name

DataSource

DataField

txtAreaCode2

datAreaCode2

AreaCode

 TextBox 

10

Name

DataSource

DataField

txtState2

datAreaCode2

State

 TextBox 

11

Name

DataSource

DataField

txtStateName2

datAreaCode2

StateName

 TextBox 

12

Name

DataSource

DataField

txtCities2

datAreaCode2

Cities

 Data 

13

Name

RecordSource

datAreaCode2

AreaCode

 Frame 

14

Name

Caption

ForeColor

fraByState

By State

&H000000FF&

 Label 

15

Name

Caption

ForeColor

lblPrompt1

Enter a state abbreviation:

&H00FF0000&

 Label 

16

Name

Caption

lblAreaCode1

Area code:

 Label 

17

Name

Caption

lblState1

State:

 Label 

18

Name

Caption

lblStateName1

State name:

 Label 

19

Name

Caption

lblCities1

Cities:

 TextBox 

20

Name

Alignment

txtStateAbbrev1

2 - Center

 TextBox 

21

Name

DataSource

DataField

txtAreaCode1

datAreaCode1

AreaCode

 TextBox 

22

Name

DataSource

DataField

txtState1

datAreaCode1

State

 TextBox 

23

Name

DataSource

DataField

txtStateName1

datAreaCode1

StateName

 TextBox 

24

Name

DataSource

DataField

txtCities1

datAreaCode1

Cities

 Data 

25

Name

RecordSource

datAreaCode1

ByState

*"編號"欄中的號碼用來標示圖32-2中表單上物件的位置。

AREACODE.FRM原始程式碼
 

Option Explicit

Private Sub Form_Load()
    `Center this form
    Me.Left = (Screen.Width - Width) \ 2
    Me.Top = (Screen.Height - Height) \ 2
    datAreaCode1.DatabaseName = App.Path & "\AreaCode.mdb"
    datAreaCode2.DatabaseName = App.Path & "\AreaCode.mdb"
End Sub

Private Sub txtAreaCode_Change()
    Dim strBookmark As String
    Dim strCriteria As String
    `Wait for user to enter all three digits
    If Len(txtAreaCode.Text) = 3 Then
        `Record current record
        strBookmark = datAreaCode2.Recordset.Bookmark
        `Search for first matching area code
        strCriteria = "AreaCode = " + txtAreaCode.Text
        datAreaCode2.Recordset.FindFirst strCriteria
        `Handle unmatched area code
        If datAreaCode2.Recordset.NoMatch Then
            Beep
            datAreaCode2.Recordset.Bookmark = strBookmark
        End If
    End If
End Sub

Private Sub txtAreaCode_KeyPress(KeyAscii As Integer)
    If Len(txtAreaCode.Text) = 3 Then
        txtAreaCode.Text = ""
    End If
End Sub

Private Sub txtStateAbbrev1_Change()
    Dim strBookmark
    Dim strCriteria
    `Wait for user to enter two-letter abbreviation
    If Len(txtStateAbbrev1.Text) = 2 Then
        `Record current record
        strBookmark = datAreaCode1.Recordset.Bookmark
        `Search for first matching state
        strCriteria = "State = `" + txtStateAbbrev1.Text + "`"
        datAreaCode1.Recordset.FindFirst strCriteria
        `Handle unmatched state abbreviation
        If datAreaCode1.Recordset.NoMatch Then
            Beep
            datAreaCode1.Recordset.Bookmark = strBookmark
        End If
    End If
End Sub

Private Sub txtStateAbbrev1_KeyPress(KeyAscii As Integer)
    KeyAscii = Asc(UCase$(Chr$(KeyAscii)))
    If Len(txtStateAbbrev1.Text) = 2 Then
        txtStateAbbrev1.Text = ""
    End If
End Sub

Private Sub mnuAbout_Click()
    `Set properties
    About.Application = "AreaCode"
    About.Heading = _
        "Microsoft Visual Basic 6.0 Developer's Workshop"
    About.Copyright = "1998 John Clark Craig and Jeff Webb"
    About.Display
End Sub

Private Sub mnuExit_Click()
    Unload Me
End Sub

Private Sub mnuContents_Click()
    cdlOne.HelpFile = App.Path & "\..\..\Help\Mvbdw.hlp"
    cdlOne.HelpCommand = cdlHelpContents
    cdlOne.ShowHelp
End Sub

Private Sub mnuSearch_Click()
    cdlOne.HelpFile = App.Path & "\..\..\Help\Mvbdw.hlp"
    cdlOne.HelpCommand = cdlHelpPartialKey
    cdlOne.ShowHelp
End Sub

以上這個程式依賴資料庫中的一個查詢ByState對資料錄依州名作排序,但這裡有另一個簡單的方法可以產生查詢。我們可以把資料庫控制項的RecordSource屬性設定為一個SQL字串,SQL是一個威力強大的資料處理工具。例如,你可以在Form_Load事件程序中加入下列這行程式碼,它產生的結果和ByState查詢的結果是一樣的:

datAreaCode1.RecordSource = "Select * from AREACODE order by State"

如果在程式中加入了這行程式碼,那麼你可以把資料庫中的ByState查詢刪掉。現在AreaCode表單上的兩個資料控制項都連結了同一個資料表:一個以區域號碼為順序重新排列資料錄,另一個用SQL指令依州名重新排列資料錄。

DataDump應用程式


利用Visual Basic,你可以很容易地在程式中處理資料庫檔案。資料存取物件(Data Access Object,DAO)模型提供了結構化物件的層級組織物件,讓你存取修改資料庫中的任何一個部分(請回到 第二十三章"資料庫的存取" 參閱有關DAO模型的資訊)。DataDump應用程式是一個簡化的公用程式,它讓你可以檢視資料庫的每一個部分,整理出所有資料欄、資料表及資料庫的內部結構。

DataDump應用程式不同於AreaCode應用程式,因為DataDump沒有用到資料控制項或其他資料連結控制項(Data-Bound Control)。DataDump只包含了一個文字方塊控制項和一個通用對話方塊控制項;其中,文字方塊控制項用來顯示分析後的資料庫內部結構,而通用對話方塊控制項則用來選擇預備加以分析的資料庫檔。我們利用迴圈巡走過DAO模型的每一個部分,分析資料庫檔案的內容,並將分析的結果顯示在文字方塊上。

DataDump應用程式執行後會列出資料庫所有的資料表 (Table)、各個資料表中所有的資料欄 (Field) 以及每一個資料欄的欄名、型別和欄位長度。這是一個非常實用的工具,你可以不必透過Microsoft Access就能看到資料庫的結構。

你可以很容易地擴充這個應用程式,使它也能列出資料庫中所有的查詢。有關完整的DAO階層組織以及其他更深入的資訊,請參閱Visual Basic的線上手冊。

在表單載入階段,DataDump表單會用通用對話方塊要求使用者選定一個資料庫檔案,如圖32-3。取得檔名後,程式才會繼續對被指定的資料庫檔案進行分析,並且把每一部分分析的結果串接在一個字串變數裡。每次執行這個程式,整個資料庫結構只被檢視一次;當表單的大小被重新調整時,分析的結果會被顯示在文字方塊控制項上。


 

 圖32-3 通用對話方塊要求使用者指定資料庫檔案

為了增加輸出結果的可讀性,我們用vbCrLf常數以及一些空白字元將輸出的字串予以格式化。文字方塊中的字型是Courier New,這種字型的每個字大小都一樣,提供了整齊縮排的效果。文字方塊控制項提供了捲軸的功能,因此,不管輸出結果有多長,使用者都能完全看到。

圖32-4顯示了BIBLIO.MDB (附在Visual Basic中)的結構。


 

 圖32-4 DataDump應用程式執行的結果

DATADUMP.FRM
 

圖32-5所顯示的是設計階段中的DataDump表單,文字方塊控制項的面積小於表單面積,不過在執行時文字方塊控制項的大小會被調整為和表單的大小相同。


 

 圖32-5 設計階段中的DataDump表單

請按照下表和後面的程式碼建立DataDump應用程式。

DATADUMP.FRM物件與屬性設定
屬性
 Form 
Name

Caption

frmDataDump

DataDump

 CommonDialog 
Name cdlOne
 TextBox 
Name

Font

MultiLine

Scrollbars

txtDB

Courier New

True

3 - Both

DATADUMP.FRM原始程式碼
 

Option Explicit

Dim strDBFileName As String
Dim strDB As String

Private Sub Form_Load()
    `Center this form
    Me.Left = (Screen.Width - Width) \ 2
    Me.Top = (Screen.Height - Height) \ 2
    `Prompt user for database filename
    cdlOne.DialogTitle = "Select a Database File"
    cdlOne.Filter = "Database(*.mdb)|*.mdb"
    cdlOne.CancelError = True
    `Check for Cancel button click
    On Error Resume Next
    cdlOne.ShowOpen
    If Err = cdlCancel Then End

    `Prepare to analyze database
    strDBFileName = cdlOne.FileName
    Me.Caption = "DataDump - " & strDBFileName
    GetStructure
End Sub

Private Sub Form_Resize()
    `Size text box to fit form
    txtDB.Move 0, 0, ScaleWidth, ScaleHeight
    `Display analysis string in text box
    txtDB.Text = strDB
End Sub

Private Sub GetStructure()
    `Looping variables
    Dim intI As Integer
    Dim intJ As Integer
    `Database objects
    Dim dbDump As Database
    Dim recDump As Recordset
    Dim tbdDump As TableDef
    Dim fldDump As Field
    `Open the database
    Set dbDump = Workspaces(0).OpenDatabase(strDBFileName)
    strDB = "Database: " & dbDump.Name & vbCrLf
    `Process each table
    For intI = 0 To dbDump.TableDefs.Count - 1
        Set tbdDump = dbDump.TableDefs(intI)
        If Left(tbdDump.Name, 4) <> "MSys" Then
                `Get table's name
            strDB = strDB & Space(3) & "Table: "
            strDB = strDB & tbdDump.Name & vbCrLf
            `Process each field in each table
            For intJ = 0 To tbdDump.Fields.Count - 1

                Set fldDump = tbdDump.Fields(intJ)
                `Get field's name
                strDB = strDB & Space(6) & "Field: "
                strDB = strDB & fldDump.Name & vbCrLf
                `Get field's data type
                strDB = strDB & Space(9) & "Type: "
                Select Case fldDump.Type
                Case dbBoolean
                    strDB = strDB & "Boolean" & vbCrLf
                Case dbByte
                    strDB = strDB & "Byte" & vbCrLf
                Case dbInteger
                    strDB = strDB & "Integer" & vbCrLf
                Case dbLong
                    strDB = strDB & "Long" & vbCrLf
                Case dbCurrency
                    strDB = strDB & "Currency" & vbCrLf
                Case dbSingle
                    strDB = strDB & "Single" & vbCrLf
                Case dbDouble
                    strDB = strDB & "Double" & vbCrLf
                Case dbDate
                    strDB = strDB & "Date" & vbCrLf
                Case dbText
                    strDB = strDB & "Text" & vbCrLf
                Case dbLongBinary
                    strDB = strDB & "LongBinary" & vbCrLf
                Case dbMemo
                    strDB = strDB & "Memo" & vbCrLf
                Case Else
                    strDB = strDB & "(unknown) & vbCrLf"
                End Select
                `Get field's size in bytes
                If fldDump.Type <> dbLongBinary And _

                    fldDump.Type <> dbMemo Then
                    strDB = strDB & Space(9) & "Size: "
                    strDB = strDB & fldDump.Size & vbCrLf
                End If
            Next intJ
        End If
    Next intI
    `Close database
    dbDump.Close
End Sub

測試DataDump應用程式


如果要測試DataDump應用程式,要事先把Microsoft DAO 3.51 Object Library設定為引用項目。

Jot應用程式
 

Jot應用程式使用多重文件界面(MDI)表單的功能,它能夠產生數個備忘錄子視窗。如果要把這個程式變成商業產品,你可能要增加許多功能並且修改現有的設計,但目前這個應用程式運用了許多實用的Visual Basic程式設計技巧,可以說已經具備了必要的功能。

這個應用程式所展示的程式設計技巧包括:如何建立多個MDI子表單、如何在MDI表單上使用熱鍵(Hot Key)、如何從程式中建立資料庫,以及如何在MDI表單的正中央放置一個圖形。

圖32-6所顯示的是執行中的Jot應用程式。工具列上的第一及第二個按鈕讓使用者能新增以及刪除備忘錄視窗(MDI子表單),其他的按鈕則負責排列備忘錄視窗的位置及視窗最小化之後的位置。當你關閉Jot應用程式時,所有的備忘錄資料都會被存放在資料庫中;當在下次執行Jot時,這些備忘錄資料又會出現在子視窗中。


 

 圖32-6 執行中的Jot應用程式

多重子視窗
 

工具列中第一個按鈕的功能在建立一張新的空白備忘錄視窗。我們在設計階段中建立了一張Note子表單frmNote,然後在第一個按鈕的ButtonClick事件程序中呼叫一個MakeNewNote程序,這個程序負責產生一份新的子表單。在MakeNewNote程序中,我們用以下這兩行程式碼產生並顯示新的備忘錄表單:

Dim newNote As New frmNote
newNote.Show

在Jot應用程式中,每一份子表單都共用相同的事件程序,因此,在這些事件程序中引用目前正被使用子表單的屬性時,我們以Me冠在屬性前面。例如,在子表單的Unload事件程序中,子表單的Caption屬性內容被存放在資料庫的一個欄位中,為了要記錄目前正在作Unload動作的子表單的Caption屬性內容,我們用Me.Caption取得其屬性內容。

MDI表單的熱鍵


在為Note子表單設定熱鍵之前,首先我們必須把Note子表單的KeyPreview屬性設為True,這樣,所有的按鍵訊息在被子表單或其他控制項進一步處理之前,都先會被子表單攔截下來加以檢查。在所有被截下來的按鍵訊息中,只有會被處理,子表單收到之後會更新子表單標題區的日期和時間。在正常情形下,子表單標題上的時間和日期是備忘錄建立時所記錄下來的,熱鍵讓使用者能夠隨時更改標題的內容。

即使定義了自己的熱鍵,你還是可以使用Windows所提供的來進行剪下、複製和貼上的動作。你可以在子表單的KeyDown事件程序中加入更多的熱鍵處理動作,但是在進行熱鍵處理動作之前,請記得把KeyAscii設為0,以防止表單對按鍵訊息做其他進一步的處理。

圖32-7所顯示的是一張進行熱鍵處理前的備忘錄子表單,而圖32-8所顯示的是熱鍵處理之後的同一張子表單,兩者標題區上的日期和時間並不相同。


 

 圖32-7 在1997年7月4日建立的子表單


 

 圖32-8 日期時間更新後的子表單

建立資料庫


當Jot表單(MDI表單)載入時,Jot表單會嘗試去開啟JOT.MDB資料庫,讀出任何先前存下來的備忘錄資料;如果這個資料庫檔案不存在,Jot表單便會忽略這個請求。資料庫是在Note子表單Unload時建立的,如果Note子表單在Unload時發現資料庫不存在,Note子表單便會執行資料庫建立的動作。以下就是Note子表單在Unload事件程序中建立資料庫所用的程式碼:

`Create empty database
Set dbJot = Workspaces(0).CreateDatabase( _
    "Jot.mdb", dbLangGeneral)
`Create table
Set tbdJot = dbJot.CreateTableDef("JotTable")
`Create field
Set fldJot = tbdJot.CreateField("JotDateTime", dbDate)
`Add new field to table's Fields collection
tbdJot.Fields.Append fldJot
`Create second field
Set fldJot = tbdJot.CreateField("JotNote", dbMemo)
`Add it to table
tbdJot.Fields.Append fldJot
`Add new table to TableDefs collection
dbJot.TableDefs.Append tbdJot
`New database is now open

在上面的程式中,我們用CreateDatabase、CreateTableDef和CreateField方法分別建立了Database物件、TableDef物件和Field物件。這些物件產生後並未和它們的父物件產生關聯,系統只是分配空間給這些資料庫物件。因此,在產生了資料庫物件之後,我們還要明確地用Append方法把子物件與父物件之間的關聯關係建立起來。例如,TableDef物件包含了一個Fields物件集合,Fields物件集合中則包含了資料表中所有的Field物件。使用Fields物件集合的Append方法便可以將某個特定的Field物件與Fields物件集合連結起來,藉此完成資料欄位與資料表的連結工作。用同樣的兩個步驟(產生物件而後連結物件),我們也用TableDefs物件集合的Append方法將資料表與資料庫連結在一起。

在MDI表單正中央放置一個圖形
 

能夠被放在MDI表單上的控制項種類並不多,一般而言,只有含Align屬性的控制項才可以被放在MDI表單上,而且這些控制項只能向表單的上界、下界、左邊和右邊靠齊。MDI表單本身雖然有一個Picture屬性,但是透過這個屬性載入的圖形只能向表單的左上角靠齊。那麼,Jot應用程式是如何把表單擺在MDI表單正中央的呢?這個圖形又如何在表單大小被調整之後,仍然維持在表單正中央呢?這是一個非常實用的技巧。

你可以把一個MDI子表單放置在MDI表單上的任何一個位置上。當然,如果把子表單的位置稍加計算,就必定能把子表單放在MDI表單的正中央。我們在Jot表單(MDI表單)的Resize事件程序裡,利用上述這個技巧,把一個顯示商標的Splash子表單定位在Jot表單的中央。

Splash表單只放置一個圖形,它的BorderStyle屬性被設為"0 - 沒有框線",而表單大小被調整為和圖形的大小一樣,因此,使用者只看到MDI表單上有一個圖形在正中央。從圖32-9和32-10中你可以看見,不管如何調整MDI表單的大小,圖形始終維持在表單的正中央。


 

 圖32-9 Jot表單的中央有一個圖形


 

 圖32-10 Jot表單的大小被改變後,圖形仍在表單中央

JOT.FRM
 

從圖32-11中你可以看到,Jot應用程式有五個檔案,而JOT.FRM是啟動表單,因此,我們先從這個表單談起。


 

 圖32-11 Jot應用程式的專案內容

圖32-12所顯示的是設計階段中的Jot表單。


 

 圖32-12 設計階段中的Jot表單

若要建立這張表單,請新增一個標準執行檔專案,在專案中加入一個MDI表單,然後按照以下這兩張表加入必要的控制項到表單中。

JOT.FRM功能表項目
標題 名稱 內縮 啟用
&File mnuFile 0 True
&New mnuNew 1 False
&Open... mnuOpen 1 False
&Save mnuSave 1 False
Save &As... mnuSaveAs 1 False
- mnuFileDash1 1 True
E&xit mnuExit 1 True
&Help mnuHelp 0 True
&Contents mnuContents 1 True
&Search for Help on... mnuSearch 1 True
- mnuHelpDash1 1 True
&About... mnuAbout 1 True
JOT.FRM (MDI) 物件與屬性設定
編號 *  屬性
 Form  Name

Caption

frmJot

Jot-a-Note

 Toolbar 

1

Name tlbToolBar
 ImageList 

2

Name imlIcons
 CommonDialog 

3

Name cdlOne

 *"編號"欄中的號碼用來標示圖32-12中表單上物件的位置 

 工具列、按鈕和工具提示 


在早期的Visual Basic中,如果要建立一個有按鈕又有工具提示(Tool Tips)功能的工具列,你必須用一些小技巧,甚至要用買來的控制項才能使應用程式具備這些功能。但現在Visual Basic本身把這項工作變得輕鬆多了。在這裡,我們要介紹如何在Jot表單上建立工具列,如圖32-12所示。

首先將按鈕上的圖片載入ImageList控制項中,在ImageList控制項上按下滑鼠右鍵,選擇「屬性」以修改控制項的屬性。在「屬性頁」的「一般」頁籤下點選"16*16"選項,然後再點選「影像」頁籤;在「影像」頁籤下按下「插入圖片」按鈕,為每一個按鈕放上圖片。

以下這張表列出了所有預備要放進ImageList控制項中的圖片。

影像索引 影像檔
1 NEW.BMP
2 DELETE.BMP
3 CASCADE.BMP
4 TILEH.BMP
5 TILEV.BMP
6 ARNGICON.BMP

表中的NEW.BMP和DELETE.BMP可以在Visual Studio光碟中的COMMON\GRAPHICS\BITMAPS\TLBR_W95目錄中找到,而CASCADE.BMP、TILEH.BMP、TILEV.BMP和ARNGICON.BMP則存放在隨書光碟中。

圖32-13顯示ImageList控制項的「屬性頁」對話方塊內容。

一旦ImageList控制項插入了所有的圖形之後,便可以把這個控制項和ToolBar控制項連結在一起。在ToolBar控制項上按下滑鼠右鍵,然後選擇「屬性」。在「屬性頁」對話方塊的「一般」頁籤下,把「影像庫」設為imlIcons,使ImageList控制項與ToolBar控制項連結。接下來點選「按鈕」頁籤,指定對應的圖形給每一個按鈕。圖32-14所顯示的是ToolBar控制項的「屬性頁」對話方塊。


 

 圖32-13 在ImageList中插入圖片


 

 圖32-14 Toolbar控制項的屬性頁對話方塊

在「屬性頁」對話方塊中的「按鈕」頁籤下,每按一下「插入按鈕」按鈕,工具列上便會新增一個按鈕,你可以在此為每個按鈕填入適當的資料。在「工具提示」一欄中填入的文字會成為程式執行時這個按鈕的工具提示文字。請在「索引鍵」一欄中填入具描述性的名稱,這部分的文字會在程式中被用來辨識不同的按鈕。在「影像」欄中,請輸入代表圖形的編號。

「樣式」屬性決定了按鈕的樣式,通常這個屬性都設為"0-tbrDefault"。如果要在按鈕與按鈕之間加大距離,只要加入另一個按鈕,並且把它的「樣式」設為"3-tbrSeparator"即可,不需要指定圖形或索引鍵給分隔按鈕。

以下這張表列出了tlbToolBar控制項所有的屬性設定值。

按鈕索引 索引鍵 樣式 工具提示 影像索引
1 New 0-tbrDefault New 1
2 Delete 0-tbrDefault Delete 2
3   3-tbrSeparator   0
4 Cascade 0-tbrDefault Cascade 3
5 TileHorizontally 0-tbrDefault Tile Horizontally 4
6 TileVertically 0-tbrDefault Tile Vertically 5
7 ArrangeIcons 0-tbrDefault Arrange Icons 6

接下來,請把下面這段程式加到Jot表單中。

JOT.FRM原始程式碼
 

Option Explicit

Public blnSave As Boolean

Private Sub MDIForm_Load()
    `Center this form on screen
    Me.Move (Screen.Width - Width) \ 2, _
        (Screen.Height - Height) \ 2
    `Load all previous notes from database
    LoadNotes
    `Display splash image
    frmSplash.Show
End Sub

Private Sub MDIForm_QueryUnload(Cancel As Integer, _
UnloadMode As Integer)
    `Prepare to save all current notes
    blnSave = True
End Sub

Private Sub MDIForm_Resize()
    `Move splash image to center of MDI form
    frmSplash.Move (Me.ScaleWidth - frmSplash.Width) \ 2, _
        (Me.ScaleHeight - frmSplash.Height) \ 2
End Sub

Private Sub mnuAbout_Click()
    `Set properties and display About form
    About.Application = "Jot"
    About.Heading = _
        "Microsoft Visual Basic 6.0 Developer's Workshop"
    About.Copyright = "1998 John Clark Craig and Jeff Webb"

    About.Display
End Sub

Private Sub mnuExit_Click()
    Unload Me
End Sub

Private Sub mnuContents_Click()
    cdlOne.HelpFile = App.Path & "\..\..\Help\Mvbdw.hlp"
    cdlOne.HelpCommand = cdlHelpContents
    cdlOne.ShowHelp
End Sub

Private Sub mnuSearch_Click()
    cdlOne.HelpFile = App.Path & "\..\..\Help\Mvbdw.hlp"
    cdlOne.HelpCommand = cdlHelpPartialKey
    cdlOne.ShowHelp
End Sub

Private Sub LoadNotes()
    Dim dbJot As Database
    Dim recJot As Recordset
    `Open database of previous notes
    On Error Resume Next
    Set dbJot = Workspaces(0).OpenDatabase("Jot.mdb")
    `If database doesn't exist, nothing to display
    If Err Then Exit Sub
    On Error GoTo 0
    `Open table of notes
    Set recJot = dbJot.OpenRecordset("JotTable")
    `RecordCount will be 1 if there are any records
    If recJot.RecordCount Then
        `Create note window for each note
        Do Until recJot.EOF

            MakeNewNote Format(recJot!JotDateTime, _
                "General Date"), recJot!JotNote
            recJot.MoveNext
        Loop
    End If
    `Empty database table for now
    dbJot.Execute "Delete * from JotTable"
    `Close recordset and database
    recJot.Close
    dbJot.Close
End Sub

Private Sub MakeNewNote(sdtDateTime As String, strNote As String)
    `Create new copy of note form
    Dim newNote As New frmNote
    `Set caption and note contents
    newNote.rtfNote.Text = strNote
    newNote.Caption = sdtDateTime
    `Display new note form
    newNote.Show
End Sub

Private Sub tlbToolBar_ButtonClick(ByVal Button As MSComctlLib.Button)
    Select Case Button.Key
    Case "New"
        MakeNewNote Format(Now, "General Date"), ""
    Case "Delete"
        Unload ActiveForm
    Case "Cascade"
        frmJot.Arrange vbCascade
    Case "TileVertically"
        frmJot.Arrange vbTileVertical
    Case "TileHorizontally"
        frmJot.Arrange vbTileHorizontal

    Case "ArrangeIcons"
        frmJot.Arrange vbArrangeIcons
    Case Else
    End Select
End Sub

SPLASH.FRM
 

這張沒有框線的表單唯一的用途是將商標圖案放到Jot表單的正中央,它只包含了一個圖片方塊控制項,用來載入JOT.BMP點陣圖(在本書的光碟中)。圖32-15顯示的是設計階段中的商標畫面表單,因為表單的BorderStyle屬性被設為"0-沒有框線",所以你看不到框線。


 

 圖32-15 設計階段中的Splash表單

若要建立這張表單,請在一個空白表單上加入一個影像控制項(Image Control),然後按照下表設定表單與控制項的屬性。

SPLASH.FRM物件與屬性設定
屬性
 Form 
Name

Caption

BorderStyle

MDIChild

ShowInTaskBar

frmSplash

frmSplash

0 - None

True

False

 Image 
Name

Picture

imgSplash

JOT.BMP

這張表單中所有的程式碼都包含在Form_Load事件程序中,當表單被載入時,影像控制項先被移到表單左上角,然後表單的大小會被調整為影像的大小。

SPLASH.FRM原始程式碼
 

Option Explicit

Private Sub Form_Load()
    `Move image to upper left corner
    imgSplash.Move 0, 0
    `Size this form to size of splash image
    Me.Width = imgSplash.Width
    Me.Height = imgSplash.Height
End Sub

NOTE.FRM
 

Note表單在執行階段會被複製成好幾份,每一份Note表單都存放著一份使用者編寫的備忘錄資料,我們用RichTextBox控制項作為表單上提供編輯功能的控制項。圖32-16顯示的是設計階段的Note表單。


 

 圖32-16 設計階段的Note表單

若要建立這張表單,請在一張空白的MDI子表單上放入一個RichTextBox控制項,按照以下這張表設定表單及控制項的屬性,然後輸入後面的程式。

NOTE.FRM物件與屬性設定
屬性
 Form 
Name

Caption

KeyPreview

MDIChild

frmNote

 frmNote 

True

True

 RichTextBox 
Name

ScrollBars

rtfNote

3 - rtfBoth

NOTE.FRM原始程式碼
 

Option Explicit

Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
    `Update date and time in caption with hot key Ctrl-T
    If KeyCode = 84 And Shift = 2 Then
        Me.Caption = Format(Now, "General Date")
    End If
End Sub

Private Sub Form_Resize()
    rtfNote.Move 0, 0, ScaleWidth, ScaleHeight
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Dim dbJot As Database
    Dim recJot As Recordset
    Dim tbdJot As TableDef
    Dim fldJot As Field

    Dim vntErrorNumber As Variant
    Dim dtmDateTime As Date
    Dim strNote As String
    `blnSave means save this note
    If frmJot.blnSave = False Then Exit Sub
    `Open database to save this note
    On Error Resume Next
    Set dbJot = Workspaces(0).OpenDatabase("Jot.mdb")
    vntErrorNumber = Err
    On Error GoTo 0
    `Create database if it does not already exist
    If vntErrorNumber Then
        `Create empty database
        Set dbJot = Workspaces(0).CreateDatabase( _
            "Jot.mdb", dbLangGeneral)
        `Create table
        Set tbdJot = dbJot.CreateTableDef("JotTable")
        `Create field
        Set fldJot = tbdJot.CreateField("JotDateTime", dbDate)
        `Add new field to table's Fields collection
        tbdJot.Fields.Append fldJot
        `Create second field
        Set fldJot = tbdJot.CreateField("JotNote", dbMemo)
        `Add it to table
        tbdJot.Fields.Append fldJot
        `Add new table to TableDefs collection
        dbJot.TableDefs.Append tbdJot
        `New database is now open
    End If
    `Get working recordset
    Set recJot = dbJot.OpenRecordset("JotTable", dbOpenTable)
    `Add new record
    recJot.AddNew
    `Prepare data for placing in record

    dtmDateTime = Me.Caption
    strNote = Me.rtfNote.Text
    If strNote = "" Then strNote = " "
    `Load fields in new record
    recJot!JotDateTime = dtmDateTime
    recJot!JotNote = strNote
    `Be sure database is updated
    recJot.Update
    `Close recordset and database
    recJot.Close
    dbJot.Close
End Sub

測試Jot應用程式
 

在測試Jot應用程式之前,必須把Microsoft DAO 3.51 Object Library設定為引用項目。另外,在「專案屬性」對話方塊中,把「啟動物件」設為frmJot。雖然Jot應用程式十分簡單,但是它提供了一個相當可靠的基礎,讓你可以依據它建立自己的MDI應用程式。