VBAの勉強を始めてみた

色々試しています。

マクロを高速化する(画面表示の更新をオフにする)

今更、私が書く必要もないかもしれませんが、マクロを高速化するために最も効果があると謳われる、

 

Application.ScreenUpdating プロパティ

 

 

の設定について紹介しておく必要があろうかと思います。

プロパティの設定はTrueかFalseの2通りです。
Application.ScreenUpdating=False ・・・・・・画面表示の更新をオフにする
Application.ScreenUpdating=True ・・・・・・画面表示の更新をオンにする(デフォルト)

 

例えば以下のようなコードがあったとします。

For i = 1 To 1000000
Range("A1").Value = Range("A1").Value + 1
Next i

これはセルA1に「1」を加算する処理を、For~Nextで百万回繰り返しています。
1が加算されるごとにリアルタイムで画面表示が更新され、デジタル時計の少数以下を見るような速さで数値がどんどん増えていきます。ですが、これは「1を加算する」という処理と同時に「画面表示を更新する」という処理を同時に行っているため、処理に時間がかかってしまいます。

 

では、処理中の「画面表示の更新」をやめてしまったらどうでしょうか?画面表示の処理にかかる負荷が軽減され、処理時間が短縮できるのではないでしょうか。

ということで、上記の処理を「画面表示更新あり」と「画面表示更新なし」の2バージョンでテストして時間を計測してみましょう。時間計測は処理前のTime関数の値と、処理後のTime関数の値を引き算して表示させます。

 

では、「画面表示更新あり」からやってみましょう。デフォルトで画面表示の更新はオンなので、何も設定する必要はありません。

----------------------

Sub 処理時間計測その1()
    Dim i As Long
   
    StartTime = Time
   
    For i = 1 To 1000000
        Range("A1").Value = Range("A1").Value + 1
    Next i
   
    StopTime = Time
    MsgBox "処理にかかった時間は" & vbCrLf & Minute(StopTime - StartTime) _
    & "分" & Second(StopTime - StartTime) & "秒"

End Sub

----------------------

f:id:kouten0430:20170902234357j:plain

「画面表示更新あり」では3分38秒かかりました。

 

次に、「画面表示更新なし」でやってみましょう。処理の前にApplication.ScreenUpdating=Falseを追記します。コードの中で再度Trueに設定するか、もしくはプロシージャを抜けるまで画面表示の更新は行われなくなります。

----------------------

Sub 処理時間計測その2()
    Dim i As Long
   
    StartTime = Time
   
    Application.ScreenUpdating = False  '画面表示の更新をオフにする
   
    For i = 1 To 1000000
        Range("A1").Value = Range("A1").Value + 1
    Next i
   
    StopTime = Time
    MsgBox "処理にかかった時間は" & vbCrLf & Minute(StopTime - StartTime) _
    & "分" & Second(StopTime - StartTime) & "秒"

End Sub

----------------------

f:id:kouten0430:20170902234644j:plain

「画面表示更新なし」では1分18秒でした。約3分の1程度、処理時間を短縮できていることが分かります。

上記2バージョンのテストを何回かやってみましたが、ほぼ同じ結果になりました。画面表示更新なしバンザイ!


おまけ
Application.ScreenUpdatingについて、疑問点が3つほどあったので自分なりに調べてみました。

1.Application.ScreenUpdatingをTrueに戻さないままプロシージャを終了した場合どうなるのか?
ウォッチ式を使ってApplication.ScreenUpdatingの値を見てみましょう。

f:id:kouten0430:20170903000412j:plain

ここでFalseになる。

 

f:id:kouten0430:20170903000508j:plain

再度、プロシージャを開始するとTrueから始まる。

プロシージャの終了後に画面表示の更新が復活することからも、Application.ScreenUpdating=Falseはプロシージャ実行中のみ適用されていることが分かります。(End SubでTrueに戻る)


2.プロシージャの中で別のプロシージャを呼び出した場合はどうなるのか?

f:id:kouten0430:20170903000736j:plain

呼び出し元の状態が適用される(Trueに戻るわけではない)


3.ステップイン実行中は画面表示はどうなる?

ステップイン実行中は、Application.ScreenUpdating=Falseであっても画面表示は更新されるようです。ステップインによる動作確認中に「あれ?」と思う人が多いのではないでしょうか。
ちなみにステップイン実行中、ウォッチ式の値ではFalseになっていますが、コード中のApplication.ScreenUpdatingにカーソルを合わせるとTrueになっています。