読者です 読者をやめる 読者になる 読者になる

t-hom’s diary

主にVBAネタを扱っているブログです。

VBA プログレスバーで体感速度を改善する

VBA ユーザーフォーム

手作業をマクロ化することで、何時間もの作業を数秒~数分で終わらせることができる。
この大きな時間削減に比べれば、マクロの実行速度が速いか遅いかなどというのは、些細なことのように思える。

しかし、関西人というのはせっかちな生き物で、画面が固まったまま数秒経過するとすぐにイライラし始める。
効率化したはずのマクロで逆にストレスが増えては本末転倒だ。

そこで、ちゃんとマクロが動作していることを示すために、プログレスバーを導入してみよう。

このようなフォームを作成する。
f:id:t-hom:20150908115120p:plain

プログレスバーは標準のツールボックスに無いので、ツールボックスの余白で右クリックしてその他のコントロールからMicrosoft ProgressBar Control, version 6.0を追加する。
f:id:t-hom:20150908114956p:plain

フォームのオブジェクト名はPleaseWaitとし、Captionを「しばらくお待ちください」に変更する。
また、フォームのShowModalプロパティはFalseに設定しておく。

大事なことなのでもう一度書く。

フォームのShowModalプロパティはFalseに設定しておく。

ShowModalがTrueだとバーが進行しない。

以下、フォームのコード

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public Speed As Integer

Public Property Get Rest()
    '100%までの残り
    With Me.ProgressBar1
        Rest = .Max - .Value
    End With
End Property

Public Sub Progress(Percent)
    '指定したパーセントだけ進む
    
    DoEvents
    'DoEventsをはさまないと、UserForm_Activateが発動せず、
    '起動時にProgressBarのValueが0にならない。
    
    If Percent > Rest Then Percent = Rest
    For i = 1 To Percent
        If i Mod Speed = 0 Then
            DoEvents
            Sleep 100
        End If
        With Me.ProgressBar1
            .Value = .Value + 1
        End With
    Next
End Sub

Private Sub UserForm_Activate()
    Me.ProgressBar1.Value = 0
End Sub

Private Sub UserForm_Initialize()
    With Me.ProgressBar1
        .Value = 0
        .Min = 0
        .Max = 100
        WaitTime = 1
    End With
End Sub

Speedは、何回に一回Sleepを挟むかを設定する。
1なら毎回、10なら10回に1回、0.1秒のスリープが入る。

以下、PleaseWaitフォームを利用する標準モジュールのコード。

Sub test()
    With PleaseWait
        .Show
        .Speed = 5
        .Progress 50
        .Speed = 1
        .Progress 30
        .Speed = 10
        .Progress 20
        .Hide
    End With
End Sub

スピードを調節しながら100%まで進捗させている。

ポイントは、メインコード側でプログレスバーコントロールの面倒を見ないということ。
もしPleaseWaitフォームにProgressプロシージャが無ければ、メインコードでPleaseWait.ProgressBar1.Value = PleaseWait.ProgressBar1.Value + 1という風にメインコードで値を管理しなければならない。
フォーム側に適切なプロシージャを作りこむことによって、メインコードがフォームに出す指示はシンプルになる。


さて、実際に利用する際だが、こまごました処理とプログレスバーの動きを同期させる必要は無い。
マクロの処理をいくつかの大きな塊に分けて、ひとつの処理の塊が終わった後にプログレスバーを何十%か進め、次の処理の塊がおわったらまた何十%か進めるといったふうに、処理と進捗表示を交互に行うと良い。

どの処理で何パーセント進めるかは、それぞれの部位の所要時間を計測すればあとは計算で求まる。

処理時間の計測方法は以下の記事に書いた。thom.hateblo.jp

まとめ

プログレスバーを導入したところで、実速度は変わらないばかりか、むしろ低下してしまう。
ただし、動きが見える分、体感速度は向上しているはずだ。
ただの気休めに過ぎないが、気が休まるならそれに越したことはない。

また、プログレスバーの表示は、「確かに実行した」と記憶にとどめる効果も期待できると思う。時々、自分で作ったマクロが一瞬でパッと終わってしまい、「あれ、この処理やったっけ?」となる場合がある。一瞬で終わる処理でもあえて1秒程度のプログレスバーアニメーションを見せることで、実行したことを記憶にとどめる効果もあるかもしれない。
(素人の憶測です。そんな効果があるかどうかは、認知心理学の分野ですね。)

以上

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。