33.公用程式

以Visual Basic發展一些實用的公用程式(Utility)是一件很簡單的工作。有時候,這些公用程式可以在你發展Visual Basic應用程式時派上用場;有時候,它們可以作為學習Visual Basic的教材。在本章中,我們要介紹三個公用程式:第一個應用程式讓你實驗滑鼠游標的特性,第二個讓你很方便地播放多媒體檔案,第三個則告訴你今天天氣的寒風降溫指數。

MousePtr應用程式
 

MousePtr應用程式是一個很實用的公用程式,它讓你快速地瀏覽16種標準的滑鼠指標,也可以讓你載入任何一個圖像檔作為滑鼠指標。

圖33-1所顯示的是執行階段的MousePtr表單,當你選擇了某一個滑鼠指標選項,滑鼠游標就會立刻改變。如果要使用某個圖像作為滑鼠游標,請選擇最後一個選項,"99 - Custom Icon"。第一次選擇這個選項時,「Select an Icon File」對話方塊會出現在螢幕上,這個對話方塊讓你選擇一個圖像檔作為滑鼠游標的圖像來源,以後你再次選擇"99 - Custom Icon"時,滑鼠游標都會使用這個圖像。如果想要改變這個圖像,請按下「Select Icon」按鈕,然後在「Select an Icon File」對話方塊中選擇另一個圖像檔。

我們在MousePtr表單上提供了一個文字方塊控制項作為學習和輔助記憶的工具。選擇"0 - Default"和"1 - Arrow"顯示出來的效果都是同樣的標準箭頭,但是當你把滑鼠游標移動到文字方塊控制項上面時,你就可以察覺兩者的差異。預設的滑鼠游標在經過文字方塊的編輯區時,形狀會由箭頭變成為I字符號,如圖33-1。然而,"1 - Arrow"選項使得滑鼠游標不管在哪裡都維持箭頭的形狀。


 

 圖33-1 執行中的MousePtr表單

圖33-2顯示EARTH.ICO圖像被選為滑鼠游標,你可以在Visual Basic光碟中找到這個圖像以及許多其他的圖像。如果你打算在應用程式中使用幾個自訂的游標,可以把這些檔案放在一個資源檔中(請參閱第 二十六章"專案發展" )。


 

 圖33-2 使用EARTH.ICO作為有趣的滑鼠游標

如圖33-3所示,這個專案包含了兩個檔案,MousePtr表單為啟動表單,About表單顯示標準的「關於」對話方塊。


 

 圖33-3 MousePtr專案的內容

MOUSEPTR.FRM
 

MousePtr表單上有一組選項按鈕供你選擇滑鼠游標的形狀。每個選項按鈕的Index屬性值將會被指定給表單的MousePointer屬性,滑鼠游標的形狀就由表單的MousePointer屬性值來決定。這些數字(選項按鈕的Index屬性值)的範圍是由0到15,另外再加上一個99來表示自訂圖像游標。

圖33-4顯示的是設計階段中的MousePtr表單。


 

 圖33-4 設計階段中的MousePtr表單

請按照下面兩張表和後面的程式來建立MousePtr應用程式。

MOUSEPTR.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
MOUSEPTR.FRM物件與屬性設定
編號 *  屬性
 Form  Name

Caption

BorderStyle

frmMousePtr

Mouse Pointers

3 - Fixed Dialog

 OptionButton 

1

Name

Caption

Index

optMousePtr

0 - Default

0

 OptionButton 

2

Name

Caption

Index

optMousePtr

1 - Arrow

1

 OptionButton 

3

Name

Caption

Index

optMousePtr

2 - Crosshairs

2

 OptionButton 

4

Name

Caption

Index

optMousePtr

3 - I-Beam

3

 OptionButton 

5

Name

Caption

Index

optMousePtr

4 - Icon

4

 OptionButton 

6

Name

Caption

Index

optMousePtr

5 - Size (N S E W)

5

 OptionButton 

7

Name

Caption

Index

optMousePtr

6 - Size (NE SW)

6

 OptionButton 

8

Name

Caption

Index

optMousePtr

7 - Size (N S)

7

 OptionButton 

9

Name

Caption

Index

optMousePtr

8 - Size (NW SE)

8

 OptionButton 

10

Name

Caption

Index

optMousePtr

9 - Size (W E)

9

 OptionButton 

11

Name

Caption

Index

optMousePtr

10 - Up Arrow

10

 OptionButton 

12

Name

Caption

Index

optMousePtr

11 - Hourglass

11

 OptionButton 

13

Name

Caption

Index

optMousePtr

12 - No Drop

12

 OptionButton 

14

Name

Caption

Index

optMousePtr

13 - Arrow and Hourglass

13

 OptionButton 

15

Name

Caption

Index

optMousePtr

14 - Arrow and Question Mark

14

 OptionButton 

16

Name

Caption

Index

optMousePtr

15 - Size All

15

 OptionButton 

17

Name

Caption

Index

optMousePtr

99 - Custom Icon

99

 TextBox 

18

Name

Text

Multiline

txtTestArea

Move mouse pointer over this text box to compare

mouse pointer settings0 - Default and 1 - Arrow.

True

 Frame 

19

Name

Caption

fraSelect

Custom icon mouse pointer

 Label 

20

Name

Caption

lblIcon

(none)

 CommandButton 

21

Name

Caption

cmdSelect

&Select Icon

 CommonDialog 

22

Name dlgOne

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

MOUSEPTR.FRM原始程式碼
 

Option Explicit

Private Sub cmdSelect_Click()
    `Prompt user for icon filename
    dlgOne.DialogTitle = "Select an Icon File"
    dlgOne.Filter = "Icon(*.ico)|*.ico"
    dlgOne.CancelError = True
    `Check for Cancel button click
    On Error Resume Next
    dlgOne.ShowOpen
    If Err <> cdlCancel Then
        `Load icon as mouse pointer
        frmMousePtr.MouseIcon = LoadPicture(dlgOne.FileName)
        `Display current icon path
        lblIcon.Caption = dlgOne.FileName
        `Select mouse pointer type 99
        optMousePtr(99).SetFocus
    End If
End Sub

Private Sub Form_Load()


    `Center this form
    Left = (Screen.Width - Width) \ 2
    Top = (Screen.Height - Height) \ 2
    `Move focus off text box and onto option buttons
    Show
    optMousePtr(0).SetFocus
End Sub

Private Sub optMousePtr_Click(Index As Integer)
    `Set selected mouse pointer
    frmMousePtr.MousePointer = Index
    `Open dialog box if no icon file previously specified
    If Index = 99 And lblIcon = "(none)" Then
        cmdSelect_Click
    End If
End Sub

Private Sub mnuAbout_Click()
    `Set properties
    About.Application = "MousePtr"
    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()
    dlgOne.HelpFile = App.Path & "\..\..\Help\Mvbdw.hlp"
    dlgOne.HelpCommand = cdlHelpContents
    dlgOne.ShowHelp

End Sub

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

ShowTell應用程式
 

ShowTell應用程式在設計上很簡單,不過它卻是個實用的工具。它讓你可以快速地瀏覽各種不同種類的影像檔(bitmap、icon、JPEG、GIF和Windowsmetafile),播放聲音檔(WAV)或是視訊檔(AVI和MPG)。

啟動表單frmShowTell為每一種檔案提供了一個指令按鈕。我們把所有檔案分成兩類加以處理:含靜態影像或圖片的會被載入到一個影像控制項中,其他動態性的檔案則交由mciExecute API函式播放。

圖33-5所顯示的是執行中的ShowTell表單。


 

 圖33-5 執行中的ShowTell表單

當表單上任何一個按鈕被按下時,表單上的通用對話方塊會要求你依指定的檔案種類選擇一個檔案,輸入的檔案如果是靜態的影像,那麼我們用另一張表單frmImage來顯示它;如果是動態的多媒體檔,則由一個API函式來播放。多媒體檔播放完畢後或是靜態影像關閉後,「開啟檔案」的對話方塊又會再度出現,讓你選擇同一種檔案類型中的另一個檔案。如果想回到主表單,在「開啟檔案」的對話方塊中按下「取消」即可。

圖33-6所顯示的是一個JPG檔,圖33-7則是一個樣本AVI檔正在播放的情形。


 

 圖33-6 以ShowTell應用程式顯示一個JPG檔


 

 圖33-7 AVI檔正在播放的情形

如圖33-8所示,ShowTell應用程式包含了兩張表單。


 

 圖33-8 ShowTell應用程式的專案內容

SHOWTELL.FRM


前面提到,ShowTell表單用一個通用對話方塊控制項來顯示「開啟檔案」的對話方塊。當這個對話方塊出現時,ShowTell表單就會被隱藏起來;如果對話方塊開啟的是影像檔,那麼,在影像檔被顯示期間,ShowTell表單仍然保持隱藏狀態,一直到影像表單被關閉後,ShowTell表單才會再度出現。如果開啟的檔案是個多媒體檔,ShowTell應用程式會在多媒體檔開始播放時,立即再叫出「開啟檔案」的對話方塊。

圖33-9所顯示的是設計階段中的ShowTell表單,表單上有一個通用對話方塊。


 

 圖33-9 設計階段中的ShowTell表單

若要建立ShowTell表單,請按照下表設定表單和控制項的屬性,然後在表單中加入後面的程式碼。

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

Caption

Icon

frmShowTell

ShowTell

Eye.ico

 Common Dialog 

1

Name dlgOne
 CommandButton 

2

Name

Caption

Index

cmdShow

Bmp

0

 CommandButton 

3

Name

Caption

Index

cmdShow

Ico

1

 CommandButton 

4

Name

Caption

Index

cmdShow

Wmf

2

 CommandButton 

5

Name

Caption

Index

cmdShow

Wav

3

 CommandButton 

6

Name

Caption

Index

cmdShow

Gif

4

 CommandButton 

7

Name

Caption

Index

cmdShow

Jpg

5

 CommandButton 

8

Name

Caption

Index

cmdShow

Avi

6

 CommandButton 

9

Name

Caption

Index

cmdShow

Mpg

7

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

SHOWTELL.FRM原始程式碼
 

Option Explicit

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

Private Sub Form_Load()
    `Center this form on screen
    Me.Move (Screen.Width - Width) \ 2, _
        (Screen.Height - Height) \ 2
End Sub

Private Sub cmdShow_Click(intIndex As Integer)
    Me.Hide
    Select Case intIndex
    Case 0
        ShowMedia "bmp"
    Case 1
        ShowMedia "ico"
    Case 2
        ShowMedia "wmf"

    Case 3
        PlayMedia "wav"
    Case 4
        ShowMedia "gif"
    Case 5
        ShowMedia "jpg"
    Case 6
        PlayMedia "avi"
    Case 7
        PlayMedia "mpg"
    End Select
    Me.Show
End Sub

Private Sub PlayMedia(strFileExt As String)
    `Process multimedia files
    Dim strFilter As String
    Dim strFile As String
    Dim lngX As Long
    strFilter = "*." & strFileExt & "|*." & strFileExt
    Do
        strFile = GetFileName(strFilter)
        If strFile = "" Then Exit Do
        lngX = mciExecute("Play " & strFile)
    Loop
End Sub

Private Sub ShowMedia(strFileExt As String)
    `Process static images
    Dim strFilter As String
    Dim strFile As String
    Dim lngX As Long
    strFilter = "*." & strFileExt & "|*." & strFileExt
    Do

        strFile = GetFileName(strFilter)
        If strFile = "" Then Exit Do
        frmImage.Display strFile
    Loop
End Sub

Private Function GetFileName(strFilter As String) As String
    `Use CommonDialog control to display a dialog box that allows
    `user to select media file
    With dlgOne
        .DialogTitle = "ShowTell"
        .Flags = cdlOFNHideReadOnly
        .Filter = strFilter
        .FileName = ""
        .CancelError = True
        On Error Resume Next
        .ShowOpen
        On Error GoTo 0
        GetFileName = .FileName
    End With
End Function

FRMIMAGE.FRM
 

這張表單被用來載入並顯示一個影像檔,表單的程式碼中只包含了一個公用方法Display,這個方法負責所有顯示影像的相關工作。Display方法唯一的參數是一個包含完整路徑的檔名。

Display方法被呼叫後,它首先將檔名指定給表單的Caption屬性,接著載入檔案、調整表單大小、把表單移到螢幕中央,最後顯示圖像。

若要建立這張表單,請在ShowTell專案中加入第二張表單,把它命名為frmImage,在表單上加入一個影像控制項imgOne,最後加入下面的程式:

FRMIMAGE.FRM原始程式碼
 

Option Explicit

Public Sub Display(strFileName As String)
    Dim lngWedge As Long
    Dim lngHedge As Long
    Me.Caption = strFileName
    With imgOne
        .Picture = LoadPicture(strFileName)
        .Move 0, 0
        lngWedge = Width - ScaleWidth
        lngHedge = Height - ScaleHeith

        Me.Move (Screen.Width - (.Width + lngWedge)) \ 2, _
            (Screen.Height - (.Height + lngHedge)) \ 2, _
            .Width + lngWedge, .Height + lngHedge
    End With
    Me.Show vbModal
End Sub

WindChil應用程式
 

WindChil應用程式採用美國國家氣象局使用的計算方法,依氣溫和風速,計算出寒風降溫指數(Windchill Index)。

這個應用程式展示了Slider控制項的用法,我們用兩個Slider控制項讓使用者指定風速和溫度。圖33-10顯示的是執行中的WindChil表單:一個滑鈕設定風速為17英哩,另一個則設定溫度為華氏32度。

這個應用程式有一些勝過傳統圖表的優點。在這個應用程式中,風速和溫度可以被設定為精準的數值,而一般的標準圖表卻必須捨位到最接近的5或10單位。其實,這個應用程式最大的優點在於它所提供的幾個選項按鈕,使用者可以選擇測量風速的單位(英哩 / 每小時或是公里 / 每小時)以及溫度的單位(華氏或是攝氏)。當使用者改變選項時,滑鈕上面的設定維持不變,但顯示出來的數字單位則已經經過了轉換。圖33-11中的設定和圖33-10中的設定一樣,只是單位不同,變成了公制單位。


 

 圖33-10 執行中的Windchill表單


 

 圖33-11 WindChil表單以公制單位顯示風速和溫度

WINDCHIL.FRM
 

在WindChil表單上,風速滑鈕控制項的Min屬性和Max屬性分別被設為5英哩和10英哩,而溫度滑鈕控制項的Min屬性和Max屬性分別被設為華氏 -50度和 +90度,超過以上範圍的值都是不正確的值。

使用滑鈕控制項,簡化了驗證資料的手續,因為使用者根本不可能輸入超出範圍的資料,因此,我們不必撰寫程式碼來檢查資料。

在"WINDCHIL.FRM物件與屬性設定"這張表中,你可以看見滑鈕控制項的LargeChange屬性被設為1,這可以讓使用者以滑鼠左鍵單擊(click)滑鈕兩側以調整風速或溫度的設定值,每次單擊滑鼠左鍵設定值就會減1 (左側)或加1 (右側)。


注意:

習慣上筆者並不喜歡使用Variant型別,因為明確的資料型別宣告會使程式執行的速度快一點,而且中間的計算結果也比較可以預測。但是在這個程式中,筆者故意要做個實驗,因此刻意把所有的變數都以Variant型別來處理。實驗結果顯示,程式執行的速度相當的快,而且計算的結果正確。

有些人認為,在撰寫程式時全部變數都使用Variant型別可以使程式設計的工作輕鬆一點,但筆者認為這仍然決定在程式的本身,不能一概而論。字串與數字之間的自動型別轉換可能相當地令人不放心,筆者本身就見過因為型別轉換不當而造成非常奇怪而且難以追蹤的轉換結果。然而,在某些應用程式中,Variant型別卻能運作無誤。


圖33-12顯示的是設計階段的WindChil表單。我們把某些標籤控制項的ForeColor屬性設為藍色或紅色,使表單的外觀更為明亮。當然,你可以選擇你喜歡的顏色。


 

 圖33-12 設計階段的WindChil表單

若要建立WindChil表單,請按照下面這兩張表設定表單和控制項的屬性,然後在表單中加入後面的程式碼。

WINDCHIL.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
WINDCHIL.FRM物件與屬性設定
編號 *  屬性
 Form  Name

Caption

BorderStyle

Icon

frmWindChill

Windchill Factor

3 - Fixed Dialog

Snow.ico

 CommonDialog 

1

Name dlgOne
 Label 

2

Name

Alignment

Font

ForeColor

lblWindChill

2 - Center

MS Sans Serif Bold 12

&H00FF0000&

 Frame 

3

Name

Caption

ForeColor

fraWindSpeed

Wind Speed

&H000000FF&

 Frame 

4

Name

Caption

ForeColor

fraTemperature

Temperature

&H000000FF&

 OptionButton 

5

Name

Caption

Value

optMPH

Miles/Hour

True

 OptionButton 

6

Name

Caption

optKPH

Kilometers/Hour

 OptionButton 

7

Name

Caption

Value

optFahrenheit

Fahrenheit

True

 OptionButton 

8

Name

Caption

optCelsius

Celsius

 Label 

9

Name

Alignment

lblWindSpeed

2 - Center

 Label 

10

Name

Alignment

lblTemperature

2 - Center

 Slider 

11

Name

LargeChange

Max

Min

sldWindSpeed

1

50

5

 Slider 

12

Name

LargeChange

Max

Min

sldTemperature

1

90

&50

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

WINDCHIL.FRM原始程式碼
 

Option Explicit

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

Private Sub mnuExit_Click()
    Unload Me
End Sub

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

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

Private Function Celsius(vntF)
    `Convert Fahrenheit to Celsius
    Celsius = (vntF + 40) * 5 / 9 - 40
End Function

Private Sub ChillOut()
    Dim vntWind
    Dim vntTemp
    Dim vntChill
    Dim strDisplay As String
    `Get working values from scrollbars
    vntWind = sldWindSpeed.Value
    vntTemp = sldTemperature.Value
    `Convert to MPH if KPH selected
    If optKPH.Value = True Then
        vntWind = Mph(vntWind)
    End If
    `Convert to Fahrenheit if Celsius selected
    If optCelsius.Value = True Then
        vntTemp = Fahrenheit(vntTemp)
    End If
    `Calculate windchill index
    vntChill = Int(0.0817 * (Sqr(vntWind) * 3.71 + _
        5.81 - 0.25 * vntWind) * (vntTemp - 91.4) + 91.4)

    `Convert back to Celsius if selected
    If optCelsius.Value = True Then
        vntChill = Celsius(vntChill)
    End If
    `Display windchill index
    strDisplay = "Windchill index is " & Str$(CInt(vntChill))
    If optFahrenheit.Value = True Then
        lblWindChill.Caption = strDisplay & " F"
    Else
        lblWindChill.Caption = strDisplay & " C"
    End If
End Sub

Private Sub cmdCancel_Click()
    `End if Cancel button clicked
    Unload frmWindChill
End Sub

Private Function Fahrenheit(vntC)
    `Convert Celsius to Fahrenheit
    Fahrenheit = (vntC + 40) * 9 / 5 - 40
End Function

Private Sub Form_Load()
    `Force scrollbars to update
    sldWindSpeed_Change
    sldTemperature_Change
End Sub

Private Sub sldTemperature_Change()
    Dim vntTmp
    `Get temperature
    vntTmp = sldTemperature.Value
    `Display using selected units

    If optCelsius.Value = True Then
        lblTemperature.Caption = vntTmp & " C"
    Else
        lblTemperature.Caption = vntTmp & " F"
    End If
    `Calculate windchill index
    ChillOut
End Sub

Private Sub sldTemperature_Scroll()
    `Update when slider knob moves
    sldTemperature_Change
End Sub

Private Sub sldWindSpeed_Change()
    Dim vntTmp
    `Get wind speed
    vntTmp = sldWindSpeed.Value
    `Display using selected units
    If optKPH.Value = True Then
        lblWindSpeed.Caption = vntTmp & " KPH"
    Else
        lblWindSpeed.Caption = vntTmp & " MPH"
    End If
    `Calculate windchill index
    ChillOut
End Sub

Private Sub sldWindSpeed_Scroll()
    `Update when slider knob moves
    sldWindSpeed_Change
End Sub

Private Function Kph(vntMph)

    `Convert MPH to KPH
    Kph = vntMph * 1.609344
End Function

Private Function Mph(vntKph)
    `Convert KPH to MPH
    Mph = vntKph / 1.609344
End Function

Private Sub optCelsius_Click()
    Dim vntC
    `Convert current temperature to Celsius
    vntC = Celsius(sldTemperature.Value)
    If vntC < -45 Then vntC = -45
    `Reset scrollbar for Celsius
    sldTemperature.Min = -45
    sldTemperature.Max = 32
    sldTemperature.Value = CInt(vntC)
    sldTemperature_Change
End Sub

Private Sub optFahrenheit_Click()
    Dim vntF
    `Convert current temperature to Fahrenheit
    vntF = Fahrenheit(sldTemperature.Value)
    If vntF < -50 Then vntF = -50
    `Reset scrollbar for Fahrenheit
    sldTemperature.Min = -50
    sldTemperature.Max = 90
    sldTemperature.Value = CInt(vntF)
    sldTemperature_Change
End Sub

Private Sub optKPH_Click()

    Dim vntK
    `Convert current wind speed to KPH
    vntK = Kph(sldWindSpeed.Value)
    `Reset scrollbar for KPH
    sldWindSpeed.Min = 8
    sldWindSpeed.Max = 80
    sldWindSpeed.Value = vntK
    sldWindSpeed_Change
End Sub

Private Sub optMPH_Click()
    Dim vntM
    `Convert current wind speed to MPH
    vntM = Mph(sldWindSpeed.Value)
    `Reset scrollbar for MPH
    sldWindSpeed.Min = 5
    sldWindSpeed.Max = 50
    sldWindSpeed.Value = vntM
    sldWindSpeed_Change
End Sub