前言:
這一個單元開始我們就要進入Screen Saver Maker的設定程式講解了, 在開始講解之前有些事情先向各位說明一下 - 在這個程式裡有很多地方並不一定要 用我所用的方法來處理,也有一些地方其實可以用某些物件來代替(像Save、Load File的視窗 其實VB早有OCX可以直接使用了,我只是基於做做看的好玩心理下才自己DIY的,前前後後還經過不 少次錯誤才完成的,其實這種地方沒有特別需求的話,直接使用原有物件就可以了,自己做反而浪費時間) ,還有些地方在我寫這個程式講解的時候發現了有更好的處理方法,沒有一個程式設計者敢誇口說他寫的程式完美無缺, 我也一樣,希望你們不光是看我的講解,在同時,也能思考,如果是你,怎麼做會更好, 這才是我設立這個網站的目的-戶動成長,人要思考才會成長,不是嗎?願共勉之。 不說廢話了,開始講解程式吧!

在Screen Saver Maker的程式裡,它的基本流程是設定為
1.利用設定視窗製作螢幕保護程式,將資料存為SPM檔
2.執行螢幕保護程式,依SPM檔的內容Show出畫面內容
所以我們就從設定視窗開始講解囉! 當然,使用者有可能不經過第一道程序就執行螢幕保護程式,這時我們的程式就必須能查出這個 錯誤再提醒使用者正確的步驟,這一點在講解螢幕保護程式執行視窗時我會說明的, 我們就先打開frmScrSetUP來看看吧。
請先觀察 Form_Activate、Form_Initialize、Form_Load三個程序, 首先From_Activate請跳過不看,這一段處理是當使用者Double Click SPM檔並指定Screen Saver Maker 為啟動的程式的自動開檔處理,不過還有一些問題要處理,所以不算是完整的功能,當你看完整段程式時 可以自行試試看將其補完,Form_Initialize及Form_Load則都是將一些參數及物件的狀態作一些初始化, 大概看一下就了解了。
接下來我們以使用者的執行步驟來觀察這個程式, 第一個步驟,不用說,當然就是將圖片加入SPM檔中,這裡用到DriveList Box、DirList Box、FileListBox 來瀏覽檔案,其中Dir Change或Driver Change時的處理算是基本功,可別忘了,比較特別的是Driver Change時的錯誤處理 有很多人常常忘了,如果你指定了一個光碟機或軟碟機,但是裡面沒有任何Disk存在的話,那可會發生錯誤的, 所以我設了一個DriveTemp的參數放置目前的工作磁碟機代碼,當發生錯誤的時候,就將Driver設為DriverTemp, 這樣才不會有問題。
接下來請先看一下cmbFileType這個ComboBox,這裡就是指定要加入的圖檔類別,在Form_Load的時候, 已經都指定好內容了,如果使用者變更了選項,再根據ListIndex的屬性來變更FileListBox的Pattern屬性, 這邊我已經在api.bas中宣告了PICTURE_TYPE_ALL等四個常數,在程式中如果可能的話,儘量以口語化的常數來取代123的數字, 別人要看的時候也會比較容易懂。
再接下來我們要處理的就是FileListBox Click的部份了,這裡我們現在應該要作的處理其實只有一樣 ,讓使用者預覽圖片而已,其它的步驟則是在後面才需要加上去的,我們先省略不看, 因為我還為程式加上了快顯功能表的功能,所以程式是寫在MouseDown的程序之中
Private Sub File1_MouseDown(Button As Integer, Shift As Integer, X As Single, y As Single)

If Button And 1 Then

   If lstAddData.ListCount > 0 Then
      '略
   End If
   
   If File1.FileName = "" Then Exit Sub
   picName$ = Dir1.Path
   If Right$(picName$, 1) <> "\" Then
      picName$ = picName$ & "\"
   End If

   picName$ = picName$ & File1.FileName

   Call Picture_PreView
      
ElseIf Button And 2 Then
   '略
End If
End Sub

這一段程式很簡單, 我們先檢查File1.FileName,然後再將完整的檔名代入picName中,再呼叫Picture_PreView來執行圖片預覽的動作 在預覽圖片的時候,我是以原圖等比例的縮圖展現的,其它還有很多種的展示方法在介面規劃的時候也有提到, 有興趣的可以嘗試看看。在這裡我佈置了一個picture Box-picSource及兩個Image Box-imgPreView及imgBackGround 來製作,picSource是放置原圖使用的,AutoSize設為True,大小與原圖相等。imgPreView則是使用者所看到的預覽縮圖, imgBackGround則為它的外框,純粹是好看的而已,沒有實質的用處,你想用其它物件來代替也行。 來看一下程式
Private Sub Picture_PreView()
Dim X%, y%, i%, ix%, iy%

On Error GoTo ErrorLoadImageFile

'Show Picture - Load Picture to the preView PictureBox & Source PictureBox
'Get Source Width & Height,Check the Max Value in preView Box
'Set preView's Value,Quit

If UCase$(prePicName$) = UCase$(picName$) And prePicName$ <> "" Then Exit Sub

Me.MousePointer = 11

imgPreView.Visible = False
DoEvents

imgPreView.Picture = LoadPicture(picName$)

imgBackGround.Visible = True
picSource.Picture = imgPreView.Picture
DoEvents

X% = picSource.ScaleWidth
y% = picSource.ScaleHeight
ix% = X%
iy% = y%

lblInfo(0).Caption = "W:" & Trim$(Str$(X%))
lblInfo(1).Caption = "H:" & Trim$(Str$(y%))

If X% > (imgBackGround.Width - 2) Or y% > (imgBackGround.Height - 2) Then
   i% = 1
   Do Until (ix% <= (imgBackGround.Width - 2) And iy% <= (imgBackGround.Height - 2))
      
      ix% = X% * (1 - 0.01 * i%)
      iy% = y% * (1 - 0.01 * i%)
      i% = i% + 1
      DoEvents
      
      If i% = 99 Then
         i% = 100
         Exit Do
      End If
   Loop
   
   If i% < 100 Then
      imgPreView.Width = ix%
      imgPreView.Height = iy%
   End If
Else
      imgPreView.Width = X%
      imgPreView.Height = y%
End If

prePicName$ = picName$

imgPreView.Left = imgBackGround.Left + ((imgBackGround.Width - imgPreView.Width) / 2)
imgPreView.Top = imgBackGround.Top + ((imgBackGround.Height - imgPreView.Height) / 2)
imgPreView.Visible = True
DoEvents

Me.MousePointer = 0

Exit Sub




ErrorLoadImageFile:
   Resume ShowErrorMsg
ShowErrorMsg:
   Me.MousePointer = 0
   picName$ = ""
   imgPreView.Picture = picSource.Picture
   imgPreView.Visible = True
   DoEvents
   
   MsgBox "圖檔載入錯誤,請確定圖檔是否損壞以及格式是否正確", 64, "圖檔載入錯誤"
   Exit Sub
End Sub


第一行的If 是用來判斷使用者是不是預覽同一張圖,如果是同一張的話,我們就不執行了, prePicName是在圖檔載入完畢後設定的(=PicName),這是因為如果圖檔太大的話,在計算圖片大小時還有載入圖片都會佔 用系統一段時間,所以能省則省,以避免不必要的延遲。接下來我們將滑鼠游標設為忙碌狀態, 將imgPreView Disible並使用Doevents方法,強迫Window先執行這一段程式,imgBackGround.Visible=True? 筆誤!筆誤!沒有任何用處,請將這一行刪除吧....然後將圖片載入imgPreView及picSource, 接下來我們便可以依picSource的ScaleWidth及ScaleHeight得知圖片的真正長寬,這裡要注意的是, 程式裡的計算都是以Pixel為單位來進行的,而Form及Picture的單位卻是以Twip來計算的,所以要 記得將ScaleMode設為3-像素,而計算時是取SclaeWidth、SclaeHeight,不是Width、Height來計算, 接下來我們要判斷圖檔長寬是否大於我們所設定的長寬(以imgBackGround為基準),如果大於我們所設定的長寬, 便進入Do-Loop迴圈,將長寬等比例縮小,執行到長寬都在標準以下,再將imgPreView的長寬設定完成,如果當圖縮小到0.01%都還比 標準長寬大的時候,那就沒辦法了(真的有這麼大的圖我也放棄了,31800*23800?),只好直接將長寬設為極限值, 至於比例不合,也只好放棄了。最後再將imgPreView Box置於imgBackGrond中央,imgPreView.Visible設為True,將滑鼠游標設回正常狀態即可, 最後要做的是錯誤處理,也許有的時候使用者指定的圖檔損毀,就會發生錯誤, 如果會發生錯誤的話,理論上一定是在imgPreView.Picture = LoadPicture(picName$)(只要計算處理沒寫錯的話), 這時picSource應該還是載入原來的圖檔,所以我們就可以將原圖載回imgPreView,Show出Mseeage Box告知使用者 錯誤訊息就可以了。
FileListBox的MultiSelect設為2-進階多重選取,這樣子使用者就可以一次加入多筆資料了, 接下來要做的就是新增功能了,在這裡是呼叫AddPictureData副程式來處理的
Private Sub AddPictureData()
If picName$ = "" Then Exit Sub

Dim i As Integer
Dim rBuf$

'Add Picture Data to List Box, Check The Select ITEM,and Check the Picture SUM
'If > Max(100) then Quit

For i% = 1 To File1.ListCount
    
    If File1.Selected(i% - 1) = True Then
       rBuf$ = Dir1.Path
       
       If Right$(rBuf$, 1) <> "\" Then
          rBuf$ = rBuf$ & "\"
       End If
       
       rBuf$ = rBuf$ & File1.List(i% - 1)
       
       If lstAddData.ListCount > 100 Then
          MsgBox "Sorry!你設定的圖檔數已超過內定的容許數目了!(>100)", 48, "系統訊息"
          Exit Sub
       End If
       
       lstAddData.AddItem rBuf$
       PictureSUM = PictureSUM + 1

    End If


Next i%

LoadFileUpdate = True
End Sub

這裡做的處理很簡單,只要從FileListBox的第一筆開始檢查,只要是被選取的資料項, 就取得它的完整名稱,Check過資料總數之後,如果沒有問題就將資料加入lstAddData中, 在這邊,其實你應該在迴圈外將Dir1.Path直接套入一個變數之中,就不用每一次都重新取得一次, 可以減少一些浪費的時間。最後,當我們將資料新增的時候,就代表了目前編輯的這個SPM檔已經經過 變更了,這裡我設了一個變數LoadFileUpdate來作識別,當使用者另開檔案時,就可以提醒他 要儲存檔案了,我用True代表已變更。
我把資料總數設定為100其實沒有任何的意義,我只是擔心資料會不會太大,會不會 造成什麼執行上的問題,如果設的更大,相對的ProFile這個陣列也要設的更大了, 這樣會不會太浪費了?事實上VB的陣列最多可以設到65535(應該沒記錯吧?), 我的擔憂其實就好比杞人憂天一樣,其實也不一定要那麼在意的,這一點你可以自己試試看, 另外提一點,我把陣列固定填上100是很不好的行為,因為,今天如果有其他的工程師想要更改 這個陣列大小,但是他卻沒有辦法確定,在程式的其他部份會不會因為這個修改造成什麼樣的錯誤, 那他就要多花一些時間來確定這個問題,建議你設一個常數如 Public Const MAX_DATA = 100來代替, 這樣如果有人要修改的話,只要變更一個地方就好了。

回到VB教學教室