30. 發展工具

本章提供了三個應用程式協助你控制Visual Basic發展環境:ColorBar幫你調整顯示器,讓你能夠掌握使用者所能看見的顏色特性;APIAddin是個增益功能,讓你能在Visual Basic發展環境下對常數、資料型別和函式宣告作搜尋、複製、貼上等編輯工作;Metric應用程式告訴你如何運用說明檔來呼叫你的應用程式。

另一個ScripDem則讓你實驗VBScript和JScript腳本語言。

ColorBar應用程式


ColorBar應用程式相當簡單,但它卻可以有效地平衡螢幕的顏色及亮度。從圖30-1中你可以看見ColorBar應用程式執行的情形,而圖30-2顯示的是專案的內容。


 

 圖30-1 執行中的ColorBar應用程式


 

 圖30-2 ColorBar應用程式的專案視窗

在執行ColorBar應用程式時,你會看見一張被分為16個長方形格子的表單,每一個長方形格子裡各填滿了一種由QBColor函式定義的顏色。如果在表單上按下滑鼠左鍵,顏色方格會朝一個方向移位;如果按下滑鼠右鍵,顏色方格會朝另一個方向移位;連續按下某個滑鼠鍵16次之後,所有的顏色方格都會回到原來的位置。

COLORBAR.FRM
 

關於COLORBAR.FRM有幾點需要在這裡特別說明。首先,我們把MinButton屬性設為False,為什麼呢?每次當使用者改變表單大小時,表單的顯示區域就會被Scale陳述式重新劃分一次,以簡化顏色方格的重繪動作,但如果當表單被最小化時,Scale陳述式會發出錯誤訊息,這個錯誤訊息並不是我們所需要的,因此,為了阻止這個錯誤訊息出現,我們把MinButton屬性設為False。在圖30-1的表單中,最小化的按鈕雖然仍看得見,但已經變成灰色的虛像,不能使用了。

表單上唯一的控制項是一個計時器控制項,如圖30-3。本來我們把畫顏色方格的動作放在表單的Paint事件程序中,當表單被放大時,Paint事件就會重繪顏色方格,但表單縮小時,Paint事件卻不起作用。為了解決這個問題,我們決定把重繪顏色方格的動作放在一個計時器控制項的Timer事件程序中,當我們需要重繪顏色方格時便把計時器控制項打開。

計時器控制項的Timer事件程序並非每隔一段時間就被呼叫一次,而是被呼叫一次以後就停止了。如果程式中其他的程序需要用到重繪方格的動作,則必須把計時器控制項的Enabled屬性設為True,使Timer事件程序得以執行。每次Timer事件程序執行完畢之後,計時器控制項的Enabled屬性都會被設定為False以關閉計時器。

我們在表單的Resize事件程序中設定計時器控制項的Enabled屬性為True,這樣就可以解決方格重繪的問題。


 

 圖30-3 設計階段中的ColorBar表單

請用以下這張表及後面的程式建立本應用程式。

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

Caption

MinButton

Icon

frmColorBar

ColorBar

False

Monitr01.ico

 Timer 
Name

Interval

tmrDrawBars

1

COLORBAR.FRM原始程式碼
 

Option Explicit

Dim mintColorShift As Integer

Private Sub Form_Load()
    `Center form on screen
    Me.Left = (Screen.Width - Me.Width) \ 2
    Me.Top = (Screen.Height - Me.Height) \ 2
End Sub

Private Sub Form_MouseDown(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
    `Shift color bars based on mouse button
    mintColorShift = (mintColorShift - Button * 2 + 19) Mod 16
    `Activate timer to draw color bars
    tmrDrawBars.Enabled = True
End Sub

Private Sub Form_Resize()
    `Activate timer to draw color bars
    tmrDrawBars.Enabled = True
End Sub

Private Sub tmrDrawBars_Timer()
    Dim intX As Integer
    Dim intY As Integer
    `Deactivate timer so that color bars are drawn only once
    tmrDrawBars.Enabled = False
    `Scale form for convenience
    Scale (4, 4)-(0, 0)
    `Fill in colors
    For intX = 0 To 3
        For intY = 0 To 3
            mintColorShift = (mintColorShift + 1) Mod 16
            Line (intX, intY)-(intX + 1, intY + 1), _
                QBColor(mintColorShift), BF
        Next intY
    Next intX
End Sub

APIAddin應用程式


APIAddin應用程式是Visual Basic發展環境中的一個增益功能,這個增益功能的功用在改善WIN32API.TXT裡API函式宣告的格式,使程式設計師能更方便地利用現成的函式宣告,將需要的函式宣告複製下來,然後貼進程式碼視窗中。圖30-4顯示的是APIAddin應用程式執行的情形,從圖中你可以看到一些API函式的宣告。

由於APIAddin應用程式是一個增益功能,因此一旦應用程式被安裝之後,你就可以直接從Visual Basic的「增益集」功能表中叫出由這個應用程式所建立的對話方塊,讓你能方便地從中複製函式的宣告,然後貼入到程式中。


 

 圖30-4 APIAddin應用程式執行的情形

轉換WIN32API.TXT檔


在我們執行APIAddin應用程式之前,必須把WIN32API.TXT轉為三個檔(已附在隨書光碟中),這三個檔是APIAddin應用程式的輸入資料檔。在這裡,我們提供了一個程式來執行轉檔的工作,你只要在一張空白表單加入這個程式,在執行時點選表單一下,然後等待"Done"訊息出現,轉檔的工作就大功告成(給你一個建議:你可以用這種無視覺界面的程式來執行一些自己使用的簡單工具程式)。這個轉檔程式包含在隨書光碟中的CVTAPIX.VBP專案裡,以下是詳細的程式內容。

WIN32API.TXT轉檔程式原始程式碼
 

Option Explicit

Private Sub Form_Click()
    Dim strA As String
    Dim strT As String
    Dim intState As Integer
    Dim intI As Integer
    Dim intJ As Integer
    Dim intK As Integer
    Dim intN As Integer
    Print "WorkingDear John, How Do I... "
    Open App.Path & "\Win32api.txt" For Input As #1
    Open App.Path & "\W32cons.txt" For Output As #2
    Open App.Path & "\W32type.txt" For Output As #3
    Open App.Path & "\W32decl.txt" For Output As #4
    Do Until EOF(1)
        Line Input #1, strA
        If InStr(strA, "Const ") Then intState = 2
        If InStr(LTrim(strA), "Type ") = 1 Then
            strA = "Private " & strA
            intState = 3
        End If
        If InStr(LTrim(strA), "Declare ") = 1 Then
            intState = 4
        End If
        If intState = 2 Then
            intI = InStr(strA, "`")
            If intI > 0 Then
                strA = Trim(Left(strA, intI - 1))
            End If
            If strA <> "" Then
                intI = InStr(strA, "Public")
                If intI = 1 Then
                    Print #2, strA

                Else
                    Print #2, "Private " & strA
                End If
            End If
        End If
        If intState = 3 Then
            If Left(strA, 1) = " " Then
                strA = Space(4) & Trim(strA)
            End If
            intJ = InStr(strA, "`")
            If intJ > 0 Then
                strA = RTrim(Left(strA, intJ - 1))
            End If
            Print #3, strA
        End If
        If intState = 4 Then
            intN = 2
            If Trim(strA) = "" Then
                Print #4, ""
            Else
                `Lop off comments
                intI = InStr(strA, ")")
                intJ = InStr(intI, strA, "`")
                If intJ > intI Then strA = Trim(Left(strA, intJ - 1))
                `Drop Alias if not different from original function
                intI = InStr(strA, "Alias")
                If intI Then
                    intJ = InStr(intI, strA, Chr(34))
                    intK = InStr(intJ + 1, strA, Chr(34))
                    strT = Mid(strA, intJ + 1, intK - intJ - 1)
                    strT = Space(1) & strT & Space(1)
                    If InStr(strA, strT) Then
                        strA = Left(strA, intI - 1) & _
                            Mid(strA, intK + 1)

                    End If

                End If
                `Locate "Lib"
                intI = InStr(strA, " Lib")
                `Insert "Private"
                Print #4, "Private Declare " & _
                    Mid(strA, 9, intI - 8) & "_"
                strA = Mid(strA, intI + 1)
                `Locate left parenthesis
                intI = InStr(strA, "(")
                Print #4, Left(strA, intI) & " _"
                strA = Mid(strA, intI + 1)
                `Locate each parameter
                Do
                    intI = InStr(strA, ", ")
                    If intI = 0 Then Exit Do
                    Print #4, Space(4) & Left(strA, intI) & " _"
                    intN = intN + 1
                    strA = Mid(strA, intI + 2)
               Loop; 
                `Locate right parenthesis
                intI = InStr(strA, ")")
                    Print #4, Space(4) & Left(strA, intI - 1) & " _"
                Print #4, Mid(strA, intI)
            End If
        End If
        If intState = 2 Then intState = 0
        If intState = 3 And InStr(strA, "End Type") > 0 Then
            intState = 0
            Print #3, ""
        End If
        If intState = 4 Then
            intState = 0

            Print #4, ""
        End If
    Loop
    Close #1
    Close #2
    Close #3
    Close #4
    Print "Done"
End Sub

執行過以上的轉檔程式後,WIN32API.TXT檔會分為三個檔:W32CONS.TXT、W32TYPE.TXT和W32DECL.TXT。W32CONS.TXT包含所有的常數,W32TYPE.TXT包含所有UDT結構的定義,而W32DECL.TXT則包含所有的API函式的宣告。轉檔程式把所有不相干的註解和多餘的空行移除以減少檔案的長度,同時也在所有的函式宣告前面加上了Private關鍵字,使函式的有效範圍縮減到最小。

在撰寫程式時,如果你輸入的函式宣告中出現函式原名與Alias名稱相同的情形,Visual Basic會自動地把Alias關鍵字刪掉,但不會刪除Alias後面的文字。這些文字沒有什麼作用,但卻佔據了W32DECL.TXT部分的空間,因此,我們讓轉檔程式把這種函式宣告裡整個Alias的部分都全部刪除。你可以比較W32DECL.TXT和WIN32API.TXT,看看這些函式宣告的不同之處。

建立APIAddin應用程式
 

從「檔案」功能表中選取「建立新專案」,叫出「建立新專案」對話方塊,從中點選「增益功能」圖像,Visual Basic會建立一個含一張表單、一個物件類別模別及一個程式模組的專案。

首先把表單改名為frmAPIAddin,把它存成APPADDIN.FRM,然後把Connect設計師存成CONNECT.DSR;最後,把專案命名為APIAddin,存成APIADDIN.VBP。圖30-5顯示的是整個專案的架構。


 

 圖30-5 APIAddin應用程式的專案視窗

CONNECT.DSR


Visual Basic會自動產生CONNECT.DSR的程式碼,在這裡我們也不需要大幅修改自動產生的程式,只要將所有的frmAddin改為frmAPIAddin即可,以下是CONNECT.DSR的詳細內容。

CONNECT.DSR始程式碼
 

Option Explicit

Public FormDisplayed          As Boolean
Public VBInstance             As VBIDE.VBE
Dim mcbMenuCommandBar         As Office.CommandBarControl
Dim mfrmAPIAddin              As New frmAPIAddin
Public WithEvents MenuHandler As CommandBarEvents

Sub Hide()
    On Error Resume Next
    FormDisplayed = False
    mfrmAPIAddin.Hide
End Sub

Sub Show()
    On Error Resume Next
    If mfrmAPIAddin Is Nothing Then
        Set mfrmAPIAddin = New frmAPIAddin
    End If

    Set mfrmAPIAddin.VBInstance = VBInstance
    Set mfrmAPIAddin.Connect = Me
    FormDisplayed = True
    mfrmAPIAddin.Show
End Sub

`------------------------------------------------------
`This method adds the add-in to VB
`------------------------------------------------------
Private Sub AddinInstance_OnConnection(ByVal Application As Object, _
    ByVal ConnectMode As AddInDesignerObjects.ext_ConnectMode, _
    ByVal AddInInst As Object, custom() As Variant _
)
    On Error GoTo error_handler
    `Save the VB instance
    Set VBInstance = Application
    `This is a good place to set a breakpoint and
    `test various add-in objects, properties, and methods
    Debug.Print VBInstance.FullName
    If ConnectMode = ext_cm_External Then
        `Used by the wizard toolbar to start this wizard
        Me.Show
    Else
        Set mcbMenuCommandBar = AddToAddInCommandBar("API Addin")
        `Sink the event
        Set Me.MenuHandler = _
            VBInstance.Events.CommandBarEvents(mcbMenuCommandBar)
    End If

    If ConnectMode = ext_cm_AfterStartup Then
        If GetSetting(App.Title, "Settings", _
            "DisplayOnConnect", "0") = "1" Then
            `Set this to display the form on connect
            Me.Show

        End If
    End If
    Exit Sub
error_handler:
    MsgBox Err.Description
End Sub

`------------------------------------------------------
`This method removes the add-in from VB
`------------------------------------------------------
Private Sub AddinInstance_OnDisconnection(ByVal RemoveMode _
    As AddInDesignerObjects.ext_DisconnectMode, _
    custom() As Variant _
)
    On Error Resume Next
    `Delete the command bar entry
    mcbMenuCommandBar.Delete
    `Shut down the add-in
    If FormDisplayed Then
        SaveSetting App.Title, "Settings", "DisplayOnConnect", "1"
        FormDisplayed = False
    Else
        SaveSetting App.Title, "Settings", "DisplayOnConnect", "0"
    End If
    Unload mfrmAPIAddin
    Set mfrmAPIAddin = Nothing
End Sub

Private Sub IDTExtensibility_OnStartupComplete(custom() As Variant)
    If GetSetting(App.Title, "Settings", _
        "DisplayOnConnect", "0") = "1" Then
        `Set this to display the form on connect
        Me.Show
    End If

End Sub

`This event fires when the menu is clicked in the IDE
Private Sub MenuHandler_Click(ByVal CommandBarControl As Object, _
    handled As Boolean, CancelDefault As Boolean _
)
    Me.Show
End Sub

Function AddToAddInCommandBar(sCaption As String) As _
    Office.CommandBarControl
    Dim cbMenuCommandBar As Office.CommandBarControl  `command bar object
    Dim cbMenu As Object
    On Error GoTo AddToAddInCommandBarErr
    `See if we can find the Add-Ins menu
    Set cbMenu = VBInstance.CommandBars("Add-Ins")
    If cbMenu Is Nothing Then
        `Not available, so we fail
        Exit Function
    End If
    `Add it to the command bar
    Set cbMenuCommandBar = cbMenu.Controls.Add(1)
    `Set the caption
    cbMenuCommandBar.Caption = sCaption
    Set AddToAddInCommandBar = cbMenuCommandBar
    Exit Function
AddToAddInCommandBarErr:
End Function

Connect設計師的主要功用是連結應用程式和Visual Basic整合發展環境 (Integrated Development Environment,IDE),使得應用程式可以和Visual Basic的主功能表、工具列和其他事件有所關聯。請務必打開線上手冊看看有關Connect設計師的部分。

APIADDIN.FRM
 

APIAddin表單在一個RichTextBox中顯示前面提到的三個檔案。為了增進程式執行的效率,每個檔案只有在使用者要求時才會被載入到一個字串變數中,而且每次執行時只會發生一次載入動作,被使用者要求顯示的檔案,會從字串中複製字串中的內容到RichTextBox的Text屬性中。圖30-6顯示的是發展中的APIAddin表單,圖30-7顯示的是執行中的表單。


 

 圖30-6 設計階段中的APIAddin表單


 

 圖30-7 執行階段中的APIAddin表單

請依照下表及後面的程式建立APIAddin表單。

APIADDIN.FRM物件與屬性設定
編號 *  屬性
 Form  Name

Caption

BorderStyle

frmAPIAddin

Win32 APIs

3 - Fixed Dialog

 OptionButton 

1

Name

Caption

Index

optAPI

Constants

0

 OptionButton 

2

Name

Caption

Index

optAPI

Types

1

 OptionButton 

3

Name

Caption

Index

optAPI

Declarations

2

 RichTextBox 

4

Name

HideSelection

Scrollbars

rtfAPI

False

3 - rtfBoth

 TextBox 

5

Name txtFind
 CommandButton 

6

Name

Caption

cmdFind

Find...

 CommandButton 

7

Name

Caption

cmdCopy

Copy

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

APIADDIN.FRM原始程式碼(continued)
 

Option Explicit

Public VBInstance As VBIDE.VBE
Public Connect As Connect

Private mstrCon As String
Private mstrTyp As String
Private mstrDec As String

Private Sub cmdCopy_Click()
    `Copy selected text to clipboard
    Clipboard.SetText rtfAPI.SelText
    `Return to user's project
    Unload Me
End Sub

Private Sub cmdFind_Click()
    Dim lngPtr As Long
    Dim strFind As String
    `Put focus on rich text box
    rtfAPI.SetFocus
    `Grab search string
    strFind = txtFind.Text
    `Determine where to begin search
    If rtfAPI.SelLength Then
        lngPtr = rtfAPI.SelStart + rtfAPI.SelLength
    Else
        lngPtr = 0
    End If
    `Use rich text box's Find method
    lngPtr = rtfAPI.Find(strFind, lngPtr)
    If lngPtr = -1 Then
        MsgBox "Search text not found"
    End If
End Sub

Private Sub Form_Load()
    `Startup showing declarations
    optAPI(2).Value = True
    txtFind.Text = ""
    Me.Show
    Me.ZOrder
End Sub

Private Sub optAPI_Click(Index As Integer)
    Select Case Index
    `Constants
    Case 0
        If mstrCon = "" Then
            LoadUp mstrCon, "W32cons.txt"
        End If
        rtfAPI.Text = mstrCon
    `Type structures
    Case 1
        If mstrTyp = "" Then
            LoadUp mstrTyp, "W32type.txt"
        End If
        rtfAPI.Text = mstrTyp
    `Declarations
    Case 2
        If mstrDec = "" Then
            LoadUp mstrDec, "W32decl.txt"
        End If
        rtfAPI.Text = mstrDec
    End Select
End Sub

Private Sub LoadUp(sA As String, sFile As String)

    Open App.Path & "\" & sFile For Binary As #1
    sA = Space(LOF(1))
    Get #1, , sA
    Close #1
End Sub

Private Sub rtfAPI_SelChange()
    If rtfAPI.SelLength Then
        cmdCopy.Enabled = True
    Else
        cmdCopy.Enabled = False
    End If
End Sub
Private Sub txtFind_Change()
    If Len(txtFind.Text) Then
        cmdFind.Enabled = True
    Else
        cmdFind.Enabled = False
    End If
End Sub

在APIAddin表單中的RichTextBox控制項是個相當有用的工具,它的水平捲軸及垂直捲軸讓使用者可以方便地瀏覽大量的檔案內容,而且它本身提供的Find方法省掉了很多寫程式的工作。當使用者搜尋的文字被找到時,游標會自動地移到發現文字的地方。

編譯增益功能
 

在編譯任何一個增益功能專案之前,必須在「設定引用項目」對話方塊中核取Microsoft Visual Basic 6.0 Extensibility和Microsoft Office 8.0 Object Library;要叫出「設定引用項目」對話方塊,請在「專案」功能表中點選「設定引用項目」。

增益功能事實上是一個ActiveX元件,它可以是DLL或是執行檔,但在大部分的情況下,增益功能大都被建成ActiveX DLL。請在「專案」功能表中選擇「APIAddin屬性」,檢查一下專案類別是否為ActiveX DLL。

編譯APIAddin增益功能時,請在「檔案」功能表中選擇「製成APIADDIN.DLL」,然後把製成的APIADDIN.DLL檔和三個API文字檔(W32CONS.TXT等檔案)存在同一目錄中。在編譯的過程中,Visual Basic會在系統登錄中加入一筆有關於APIADDIN.DLL的記錄,系統登錄藉這筆記錄就可以知道這個DLL檔所存放的目錄。

如果想試用APIAddin增益功能,請建立一個新的標準執行檔,然後從「增益集」功能表中選擇「增益功能管理員」,你應該會看到「APIAddin」在「增益功能管理員」對話方塊中;請選擇「APIAddin」,在「載入行為」下面選取「載入 / 載出」,然後按下「確定」。接下來,再一次點選「增益集」功能表,你這次會看見「APIAddin」,點選這個選項之後「Win32 APIs」對話方塊就會出現。到這裡,我們的APIAddin增益功能就算完成,而且隨時可以在Visual Basic發展環境中使用了。

Metric應用程式
 

Metric應用程式十分簡單,但它卻表現了Visual Basic應用程式結合線上說明檔案所產生的強大功能。Metric應用程式可以分為兩個主要部分,METRIC.HLP檔和METRIC.EXE。METRIC.HLP檔除了具備易於讀懂的說明文字外,它更運用了超文字焦點(Hypertext Hot Spot)和快顯視窗等界面技術;另一方面,METRIC.EXE可以播放聲音和視訊,執行度量衡單位的轉換,以及測試使用者對度量衡單位的了解程度。

當METRIC.EXE執行時,它首先檢查你是否用了命令列參數;假設你是以連續點選二下圖像(在「檔案總管」或是「桌面」上的圖像)的方式啟動程式,程式中不會有任何命令列參數被傳入,因此它會立刻執行METRIC.HLP檔。我們在METRIC.HLP的主題視窗中提供了幾個按鈕,以便隨時可以跳回METRIC.EXE;這些按鈕各自都會傳入一些命令列參數給METRIC.EXE,METRIC.EXE便可以根據不同的參數值來決定要採取什麼樣的動作。這些執行動作包括:播放聲音或視訊檔,顯示測驗用的對話方塊(如圖30-8),以及進行度量衡單位的計算等等。當某個執行動作

結束時,METRIC.EXE也跟著結束,使用者又會再度回到METRIC.HLP的界面中。


 

 圖30-8 從METRIC.HLP檔中啟動的測驗題表單

建立Metric應用程式


Metric應用程式的Visual Basic部分(METRIC.EXE)包括三個檔案,如圖30-9所示。


 

 圖30-9 Metric專案的內容

METRIC.BAS模組包含了這個應用程式大部分的程式碼,其中包括啟動程序Sub Main;METRIC.FRM表單用來顯示測驗題的樣本;而CONVERT.FRM表單則幫使用者換算公尺為英尺以及換算公分為英寸。

METRIC.BAS


METRIC.BAS模組包含了啟動程序Sub Main,在Sub Main程序中,我們用一個GetParms程序來擷取命令列參數,然後把參數放在公共陣列gstrParm裡;不管有沒有任何命令列參數被傳進來,gstrParm(0) 所內含的值都必定是可執行檔的檔名和路徑。

根據命令列的參數值,Sub Main會播放一個多媒體檔,顯示測驗用的對話方塊,或是執行度量衡單位的計算。你可以修改Select Case的部分來增加你自己想要的功能。

METRIC.BAS使用兩個API函式:mciExecute用來播放多媒體檔,WinExec則啟動METRIC.HLP檔。( 我們在 第十七章 曾用其他的方法啟動說明檔 ) 其實,WinExec可以啟動任何Windows應用程式,你不妨試試用WinExec啟動Windows 95的「小算盤」。

TakeAction程序告訴你如何使用Optional關鍵字來處理數目不同的參數。

METRIC.BAS原始程式碼
 

Option Explicit

Private Declare Function WinExec _
Lib "kernel32" ( _
    ByVal lpCmdLine As String, _
    ByVal nCmdShow As Long _
) As Long

Private Declare Function mciExecute _
Lib "winmm.dll" ( _
    ByVal lpstrCommand As String _
) As Long

Public gstrParm() As String

Sub Main()
    GetParms
    Select Case UBound(gstrParm)
    Case 0
        TakeAction
    Case 1
        TakeAction gstrParm(1)
    Case 2
        TakeAction gstrParm(1), gstrParm(2)

    End Select
End Sub

Private Sub TakeAction(Optional vntCmd, Optional vntFil)
    `If no parameters, open help file
    If IsMissing(vntCmd) Then
        WinExec "Winhelp.exe " & App.Path & "\Metric.hlp", 1
        Exit Sub
    End If
    `First parameter determines action to take
    Select Case UCase(vntCmd)
    `Display units conversion form
    Case "M2F", "C2I"
        frmConvert.Show
    `Play a sound file
    Case "WAV"
        Select Case vntFil
        Case 1
            mciExecute "Play Sound1.wav"
        End Select
    `Play a video clip
    Case "AVI"
        Select Case vntFil
        Case 1
            mciExecute "Play Clouds.avi"
        End Select
    `Display a quiz form
    Case "QUIZ"
        frmMetric.Show
    End Select
End Sub

Private Sub GetParms()
    Dim strCmd As String

    strCmd = Trim("X" & Space(1) & Command)
    gstrParm() = Split(strCmd)
    If Right(App.Path, 1) <> "\" Then
        gstrParm(0) = App.Path & "\" & App.EXEName
    Else
        gstrParm(0) = App.Path & App.EXEName
    End If
End Sub

METRIC.FRM


當使用者在說明對話方塊中按下「Quiz」按鈕後,METRIC.FRM表單便會顯示一份測驗的樣本,樣本中包含是非題、填空題和選擇題。圖30-10顯示的是發展中的Metric表單, 圖30-8 顯示的則是執行中的Metric表單。請按照下表及METRIC.FRM的程式碼建立這張表單。


 

 圖30-10 設計階段中的Metric表單
METRIC.FRM物件與屬性設定
編號 *  屬性
 Form  Name

Caption

frmMetric

Metric System - Quiz 1

 Label 

1

Name

Caption

Label1

1) A meter is slightly longer than a yard.

 Label 

2

Name

Caption

Label2

2) A hectare is equal to how many acres?

 Label 

3

Name

Caption

Label3

3) Select the correct prefix multiplier value(s) from the following:

 Option1 

4

Caption True
 Option2 

5

Caption False
 Text1 

6

Text (blank)
 Check1 

7

Caption exa 10^17
 Check2 

8

Caption giga 10^9
 Check3 

9

Caption femto 10^-15
 Check4 

10

Caption krypto 10^18
 Check5 

11

Caption deka 10^1
 Check6 

12

Caption atto 10^-18
 CommandButton 

13

Name

Caption

cmdOK

OK

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

METRIC.FRM原始程式碼
 

Option Explicit

Private Sub cmdOK_Click()
    MsgBox "This example quiz is not graded."
    Unload Me
End Sub

CONVERT.FRM


Convert表單是一個對話方塊,它可以幫使用者做一些數字計算,在這個應用程式中,它被用來換算公尺為英呎以及換算公分為英吋。這些都是一些簡單的計算,你可以自己加入更複雜的計算功能。圖30-11是發展階段的CONVERT.FRM。圖30-12是執行中的CONVERT.FRM。


 

 圖30-11 設計階段中的Convert表單


 

 圖30-12 執行階段中的Convert表單

請用下表及後面的程式來建立CONVERT.FRM。

CONVERT.FRM物件與屬性設定
編號 *  屬性
 Form  Name

Caption

BorderStyle

frmConvert

Metric Conversions

3 - Fixed Dialog

 Label 

1

Name

Caption

lblMeters

Enter meters:

 Label 

2

Name

Caption

lblFeet

Equivalent feet:

 Label 

3

Name

Caption

lblCentimeters

Enter centimeters:

 Label 

4

Name

Caption

lblInches

Equivalent inches:

 TextBox 

5

Name txtMeters
 TextBox 

6

Name

Enabled

txtFeet

False

 TextBox 

7

Name txtCentimeters
 TextBox 

8

Name

Enabled

txtInches

False

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

CONVERT.FRM原始程式碼
 

Option Explicit

Private Sub Form_Load()
    txtMeters.Text = "0"
    txtCentimeters.Text = "0"
End Sub

Private Sub txtCentimeters_Change()
    txtInches.Text = CStr(CDbl(txtCentimeters.Text) * 0.393700787402)
End Sub

Private Sub txtMeters_Change()
    txtFeet.Text = CStr(CDbl(txtMeters.Text) * 3.28083989501)
End Sub

METRIC.HLP
 

到底METRIC.EXE是如何從METRIC.HLP檔中被啟動的呢?我們不從建立說明檔的每一個細節談起,僅就重要的步驟來加以討論。我們用Blue Sky Software公司的產品── RoboHelp 95建立METRIC.HLP檔,RoboHelp可以讓設計者很容易地在按鈕和焦點上加入巨集,這些巨集就是啟動外部應用程式如METRIC.EXE的關鍵。

你也可以用其他建立說明檔的工具,如Visual Basic的Microsoft Help Workshop (HCW.EXE),來建立說明檔的巨集與按鈕,或者你也可以用Rich Text File (RTF)文件的註腳,完全由自己完成類似的功能。關於指令按鈕與巨集的語法,請參考Microsoft Help Workshop的線上說明。以下便是METRIC.RTF原始碼中的巨集:

Conversions:
{button Meters to feet, ExecProgram("Metric.exe M2F")} 
{button Centimeters to inches, ExecProgram("Metric.exe C2I")} To hear 
a {button Sound, ExecProgram("Metric.exe wav 1")} click this button, 
and to see a sample {button Video clip, 
ExecProgram("Metric.exe avi 1")} click here. When you're ready, 
click this {button Quiz, ExecProgram("Metric.exe QUIZ 1")} button.

每一對大括弧內的資料都會被說明檔編譯器用來建立一個指令按鈕,每個指令按鈕都可以啟動外部程式METRIC.EXE。這些巨集是說明檔的標準功能,RoboHelp將使用巨集的方法解釋得很清楚。圖30-13顯示的是啟動後的METRIC.HLP,上面所有的指令按鈕都可以呼叫METRIC.EXE。


 

 圖30-13 執行中的METRIC.HLP說明檔

ScripDem應用程式
 

Script控制項不包含在Visual Basic裡,但你可以從Microsoft網站 (http://www.microsoft.com) 上面下載這個控制項。把Script控制項安裝完畢之後,你可以從「專案」功能表叫出「設定使用元件」對話方塊,選取Microsoft Script Control 1.0,這樣就可以開始使用Script控制項。

Script控制項可以執行VBScript或是JScript原始程式碼,這兩者都可以建立起一個獨立的VBScript發展環境。ScripDem應用程式雖然算不上是一個完整的發展環境,但它告訴你如何建立發展環境,並且可以讓你執行一些簡單的VBScript程式。

ScripDem的主表單包含了一個可供輸入程式碼的文字方塊以及一個執行程式碼的Script控制項。程式中的語法錯誤將會被顯示出來,但執行時期錯誤則較難被追蹤。請務必先研究VBScript語言,以避免程式裡有太多的錯誤。這個應用程式也示範了使用Toolbar控制項的方法,這個Toolbar控制項所使用的圖案存放在一個ImageList控制項裡,Toolbar控制項中的每一個按鈕都對應到功能表中的每一項功能。我們把每個按鈕的ToolTipText屬性和Key屬性都設成一樣。ToolTipText屬性顯示每個按鈕的用途而Key屬性則指出哪一個按鈕被按下。

Run功能表(和Run按鈕)讓你選擇用VBScript還是JScript語言,而以VBScript作為預設的語言。圖30-14顯示的是執行中的ScripDem表單,上面顯示著測試中的腳本程式碼,圖中的訊息方塊則是Run按鈕被按下後的結果。圖30-15顯示的是ScripDem應用程式的專案內容。


 

 圖30-14 執行中的ScripDem應用程式


 

 圖30-15 ScripDem的專案內容

SCRIPDEM.FRM
 

如圖30-16所示,ScripDem表單中包含Toolbar控制項、ImageList控制項、文字方塊控制項、Script控制項和CommonDialog控制項。文字方塊和Script控制項用來編修和執行VBScript程式碼,而CommonDialog控制項則用來載入和儲存VBScript程式碼。


 

 圖30-16 發展階段中的ScripDem表單

要建立這個應用程式,請按照下表設定表單和控制項的屬性,然後加入後面的程式碼。請確定Toolbar控制項的ImageList屬性被設定為ilsToolbar,然後按順序在tlbToolbar中加入每一個按鈕。

SCRIPDEM.FRM功能表項目
標題 名稱 內縮 核取 啟用
&File mnuFile 0 True  
&New mnuNew 1 True  
&Open mnuOpen 1 True  
&Save mnuSave 1 True  
- mnuFileSep1 1 True  
&Print mnuPrint 1 True  
- mnuFileSep2 1 True  
E&xit mnuExit 1 True  
&Edit mnuEdit 0 True  
Cu&t mnuCut 1   True
&Copy mnuCopy 1   True
&Paste mnuPaste 1   True
&Run mnuRun 0   >True
&VisualBasic mnuVB 1 Yes True
&Java mnuJava 1 No True
- mnuRunSep1 1   True
&UpdateProcedures mnuUpdate 1   True
- mnuRunSep2 1   True
&Help mnuHelp 0   True
&Contents mnuContents 1   True
&Search For Help On mnuSearch 1   True
- mnuHelpSep1 1   True
&About mnuAbout     True
SCRIPDEM.FRM物件及屬性設定
屬性 設定值
 Form 
Name

Caption

Icon

frmScripDem

Script Demo

Wrench.ico

 Toolbar 
Name

ImageList

tlbToolbar

ilsToolbar

 ImageList 
Name

Images

ilsToolbar

New, Open, Save, Print, Cut, Copy, Paste, and Run

 CommonDialog 
Name cdlOne
 TextBox 
Name

Scrollbars

MultiLine

txtModule

3 -Both

True

 Script 
Name

Language

scrVB

VBScript

SCRIPDEM.FRM的原始程式碼
 

`SCRIPDEM
Option Explicit

Dim mfilScript As New Scripting.FileSystemObject
Dim mtexScript As TextStream
Dim mblnFileChanged As Boolean

Private Sub Form_Load()
    `Center this form
    Me.Move (Screen.Width - Me.Width) \ 2, _
        (Screen.Height - Me.Height) \ 2
End Sub
Private Sub Form_Resize()
    `Resize edit area to fill form
    txtModule.Move 0, tlbToolbar.Height, _
    Me.ScaleWidth, Me.ScaleHeight - tlbToolbar.Height
End Sub

Private Sub mnuAbout_Click()
    `Set properties and display About form
    About.Application = "ScripDem"
    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 mnuJava_Click()
    mnuVB.Checked = False
    mnuJava.Checked = True
    scrVB.Language = "JScript"
End Sub

Private Sub mnuOpen_Click()
    `If previous file has changed, prompt user to save
    If mblnFileChanged Then mnuNew_Click
    `Display Open File common dialog box
    cdlOne.DialogTitle = "Open File"
    cdlOne.ShowOpen
    `If user doesn't select a file, exit procedure
    If cdlOne.FileName = "" Then Exit Sub
    `Create text stream from FileSystemObject object
    Set mtexScript = mfilScript.OpenTextFile( _
        cdlOne.FileName, ForReading, True)
    `If file is empty or doesn't exist, don't read it
    If mtexScript.AtEndOfStream Then
        `Clear text box
        txtModule.Text = ""
    Else
        `Load text from text stream into text box
        txtModule.Text = mtexScript.ReadAll
    End If
    `Close file and text stream
    Set mtexScript = Nothing
    `Reset mblnFileChanged flag
    mblnFileChanged = False
    `Update list of procedures
    mnuUpdate_Click
End Sub

Private Sub mnuPrint_Click()

    `Simple dump to printer
    Printer.Print txtModule.Text
    Printer.EndDoc
End Sub

Private Sub mnuSave_Click()
    `Display Save File common dialog box
    cdlOne.DialogTitle = "Save File"
    cdlOne.ShowSave
    `If user cancels, exit
    If cdlOne.CancelError Then Exit Sub
    `Create text stream using FileSystemObject object
    Set mtexScript = mfilScript.OpenTextFile( _
        cdlOne.FileName, ForWriting, True)
    `Write text box text to text stream
    mtexScript.Write txtModule.Text
    `Close text stream and FileSystemObject object
    Set mtexScript = Nothing
    `Reset mblnFileChanged flag
    mblnFileChanged = False
    `Update procedures
    mnuUpdate_Click
End Sub

Private Sub mnuRunSep2_Click(Index As Integer)
    `Catch runtime errors
    On Error GoTo RunErr
    `Run selected procedure
    scrVB.Run scrVB.Procedures(Index).Name
    Exit Sub
RunErr:
    HandleError
End Sub


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

Private Sub mnuUpdate_Click()
    `Check for errors when code is parsed during
    `loading
    On Error GoTo LoadErr
    `Clear code
    scrVB.Reset
    `Add new code to Script control
    scrVB.AddCode txtModule.Text
    Dim proItem As Procedure
    Dim intCount As Integer
    `Unload menu items
    For intCount = 1 To mnuRunSep2.UBound
        Unload mnuRunSep2(intCount)
    Next intCount
    intCount = 0
    `Add procedure names to menu
    For Each proItem In scrVB.Procedures
        intCount = intCount + 1
        Load mnuRunSep2(intCount)
        mnuRunSep2(intCount).Caption = proItem.Name
    Next proItem
    Exit Sub

LoadErr:
    HandleError
End Sub

Private Sub mnuNew_Click()

    Dim intSave As Integer
    `Check whether file has changed
    CheckForChange
    txtModule.Text = ""
    mblnFileChanged = False
    `Update procedure list
    mnuUpdate_Click
End Sub

Private Sub mnuExit_Click()
    Dim intSave As Integer
    `Check whether file has changed
    CheckForChange
    `Unload form (ends application)
    Unload Me
End Sub

Private Sub mnuVB_Click()
    mnuVB.Checked = True
    mnuJava.Checked = False
    scrVB.Language = "VBScript"
End Sub

Private Sub tlbToolbar_ButtonClick(ByVal Button As ComctlLib.Button)
    Select Case Button.Key
    Case "New"
        mnuNew_Click
    Case "Open"
        mnuOpen_Click
    Case "Save"
        mnuSave_Click
    Case "Print"
        mnuPrint_Click
    Case "Cut"

        txtModule.SetFocus
        SendKeys "^x"
    Case "Copy"
        txtModule.SetFocus
        SendKeys "^c"
    Case "Paste"
        txtModule.SetFocus
        SendKeys "^v"
    Case "Run"
        PopupMenu mnuRun
    Case Else
        MsgBox "Unknown toolbar button clicked!", vbCritical
    End Select
End Sub

Private Sub txtModule_Change()
    `Set mblnFileChanged flag
    mblnFileChanged = True
End Sub

Private Sub CheckForChange()
    If mblnFileChanged Then
        Dim intSave As Integer
        `If file has changed, prompt user to save changes
        intSave = MsgBox("File has changed, save changes?", _
            vbYesNo, "Save Changes?")
        `If user decides to save, run Save menu procedure
        If intSave = vbYes Then
            mnuSave_Click
        End If
    End If
End Sub

Private Sub HandleError()

    Dim intCount As Integer
    With scrVB.Error
        `Move cursor to beginning
        txtModule.SelStart = 0
        `Move cursor to line with error
        For intCount = 1 To .Line
            SendKeys "{Down}", True
        Next intCount
        `Move cursor to column with error
        For intCount = 1 To .Column
            SendKeys "{Right}", True
        Next intCount
        `Display error
        If .Number <> 0 Then
            MsgBox Join(Array(.Source, .Number, .Description)), _
                vbCritical
        End If
    End With
End Sub

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