Excel VBA入門(8): 代碼調試/錯誤處理/代碼優化


VBE有豐富的調試工具, 比如立即窗口, 本地窗口, 監視窗口, 斷點調試...

第一個博文中已經講過調試的基本操作: 設置斷點, F5運行, F8逐條運行

斷點就是程序中暫停停止運行的位置, 設置斷點之后, 當運行到斷點行所在的語句程序就進入中斷模式,

此時在本地窗口和立即窗口中 可以查看變量以及對象的屬性值.

1. debug 介紹: 調試工具的基石

debug.print x   在不中斷程序的情況下輸出x 的值

debug.assert 與if 類似, 用與判斷一個條件是否成立, 但是if 語句不會暫定程序的執行, 如果assert方法的參數不成立,

程序會暫停進入中斷模式. 

Function assert_test(x As Integer, y As Integer) As Double
    Debug.Assert y <> 0  ' y=0則進入中斷模式
    If y <> 0 Then
        assert_test = x / y
    End If
End Function
Sub test()
    MsgBox assert_test(10, 2) ' 正常運行
    MsgBox assert_test(10, 0) ' 在Debug.Assert y <> 0 程序會中斷
End Sub

立即窗口的使用 : 立即窗口的輸出如果超過200行, 就只顯示最后200行的內容

打印的關鍵字是 print 或者?

print assert_test(10,3)
 3.33333333333333 
?sqr(2)  ' 按下Enter
 1.4142135623731 

其他

for each sh in sheets: debug.Print sh.name: next  ' Enter
Sheet8
Sheet9
Sheet10

其他

for i =1 to 4 : debug.Print i*i: next i
 1 
 4 
 9 
 16 

本地窗口的使用: 單步調試下, 本地窗口可以查看當前過程的所有變量和對象的狀態(視圖-->本地窗口), 很簡單不敘述了...

監視窗口比本地窗口靈活, 可以自己選擇想要查看的變量, 這個在Excel入門系列第一篇博文中已經講過...

2. 錯誤處理

一般錯誤分為三種: 

(1) 編輯錯誤: 不正確的代碼導致的, 沒有end  if 等

(2) 運行時錯誤: 試圖執行一個不可能完成的任務: 重命名已經打開的文件, 被除數是0....

(3) 邏輯錯誤: 語法正確, 操作正當情況下還是沒有出想要的結果

on error 語句捕捉錯誤並進行處理, 告訴程序發生錯誤時需要轉到哪個地方進行處理

on error goto line | resume next | goto 0

on error goto line 啟動錯誤處理程序, line 參數表示行標簽或者行號, 必須和 on error 在同一個過程中.

Sub errtest()
    On Error GoTo errhandle   'errhandle為標簽
    ChDrive "A"
    Exit Sub
errhandle:
    MsgBox "程序出錯, 請聯系技術人員" & vbCrLf & "錯誤編號:" & _
    Err.Number & "," & Err.Description, vbInformation, "錯誤提示"
    Err.Clear
End Sub

vbcrlf 表示換行

chDrive "A" 表示磁盤驅動器A沒有插入軟盤時將彈出 設備不可用的 提示

得到結果: 

或者用行號表示, 隨便一個數字就行! 不是真的行號

Sub errtest()
    On Error GoTo 11   'errhandle為標簽
    ChDrive "A"
    Exit Sub
11 MsgBox "程序出錯, 請聯系技術人員" & vbCrLf & "錯誤編號:" & _
    Err.Number & "," & Err.Description, vbInformation, "錯誤提示"
    Err.Clear
End Sub

如果發生錯誤不影響后面的程序, 那么直接就寫 on error resume next

3. 代碼優化

實例1: 一般工作表函數比普通VBA代碼更有效率

Sub test()
    Dim num As Long, i As Integer, tm As Date
    Dim Cell
    tm = Timer
    For i = 1 To 1000  ' 只是為了增加循環次數
        For Each Cell In Range("A1:A80")
        num = num + Cell.Value
        Next
    Next i
    Debug.Print "普通運行時間1:" & Format((Timer - tm), "0.0000") & ""
    
    tm = Timer
    For i = 1 To 1000
        num = WorksheetFunction.Sum(Range("A1:A80"))
    Next i
    Debug.Print "用sum函數的運行時間2:" & Format((Timer - tm), "0.0000") & ""
End Sub

普通運行時間1:0.3359秒

用sum函數的運行時間2:0.0078秒. 

 實例2:  減少對象的激活或者選擇

初學者很喜歡用錄制宏, 但是錄制宏得到代碼很冗余, 有很多的select , activate 語句, 實際上很多對象的操作是不需要激活該對象的.

例如當前工作表是sheet1, 現在要給sheet2 的區域A1 賦值

' 錄制宏得到的
Sheet2.Select
Range("A1").Select
ActiveCell.Value = "Hello"
' 實際很簡單
Sheet2.Range("A1").Value = "Hello"

實例3: 少用variant 類型的變量

variant 比較省事, 但是variant 需要占用很多的內存,(integer 占用2個字節, long數據占用4個字節, 全數字的variant 數據占用16個字節)

 你可以設置不同的變量進行運算10000次比較運行時間.

實例4:  減少用.  點的數量

對於對象屬性的調用, 一般采用  object.method.  點的數量越少速度越快. 

對同一對象的重復引用, 可以設置一個變量

ThisWorkbook.Sheets("try").Cells(1, 1) = 1
ThisWorkbook.Sheets("try").Cells(1, 2) = 3
ThisWorkbook.Sheets("try").Cells(1, 3) = 4

' set
Set w = ThisWorkbook.Sheets("try")

也可以用with 語句

With ThisWorkbook.Sheets("try")
    .Cells(1, 1) = 100
    .Cells(1, 2) = 200
End With

實例4: 用數組代替range

如果只對range對象中的單元格的值進行處理, 而不用到單元格的屬性和方法, 可以使用數組處理range對象.

數組的處理速度遠遠快於range對象的運算速度

Dim arr()
arr = Range("A1:E400") ' 生成一個400行6列的二維數組

數組arr必須定義為variant 類型, 數組的下表下界是1, 並且不受option base 的影響.

注意, 即使引用的范圍只有一行或者一列, 賦值的數組仍然是二維數組

 arr(range("A1:A4"))

賦值之后, arr即為一個arr(1 to 44, 1 to 1)的二維variant 數組, 元素的下標為arr(1,1), arr(2,1), arr(3,1), arr(4,1).

經過數據處理之后, 把數組變量寫入工作表區域中: range("A1:E400")=arr

實例5: 讓代碼"專注"運行--> 關閉屏幕刷新

在過程的一開始寫:  Application.ScreenUpdating = False

在結果的時候Application.ScreenUpdating = True  還原設置

實例6: 單元格/區域的表示方法

cells(1,1), range("A1"), [A1]  三種方法中cells(1,1)是最快的, [A1]最慢

但是三種方法各有各的優點, cells(1,1)可以精確的獲得單元格的行列, range("A1") 可以獲得屬性與方法

對於工作表, sheets(1)  比sheets("sheet1") 速度快, 其實VBA看到名稱時, 先把名稱解析為索引.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM