ExcelのVBAで繰り返し計算させるときに、進捗度をステータスバーに表示させています。

ループのカウンターやトータルの回数を表示させたり、

長い計算の時は、計算し終わった分の一回当たりの処理時間を求めて、

それに残り回数をかければ、あとどれぐらいで処理が終わるかの推定ができますから

それも合わせて表示させたりしています。

 

しかし、トータルの回数は多いけれども、一回の処理時間が短い時に、

毎回ステータスバーの表示を更新していると、処理が遅くなります。

 

理由は「ステータスバーに表示するから」です。

進捗を知るために、結果的に処理速度を落としては意味がありません。

 

そこで、ステータスバーに表示する回数の目安を調べました。

 

まず、ステータスバーに何かを表示するのにかかる時間です。

下のマクロを実行して時間を調べました。(あくまで私のパソコンでの時間です。)

結果は、約2ミリ秒でした。

 

ある繰り返し処理で、一回の処理に Xミリ秒かかるときに、

毎回ステータスバーに何かを表示すると、(X+2)/X = 1 + 2/X に処理時間が伸びます。

そこで、n回に一度ステータスバーに表示をすれば 1 + 2/(X*n) の処理時間に伸びます。

どれぐらい伸びても良いか、どれぐらいの間隔で表示したいのか、

でnを決めればよいことになります。

ただ、これだと目的の処理時間Xを知っていないといけません。

 

そこで、ステータスバーに何か表示をするときに、Y秒おきにしか表示しないとすれば

目的の処理時間はとりあえず考えなくてよいことになります。この場合は、

(Y+2)/Y = 1 + 2/Y に処理時間が伸びます。

Yを1秒にとれば 0.2%の増加、

0.5秒にとれば0.4%の増加、

0.2秒にすれば1%の増加になります。

 

0.5秒ごとぐらいで表示が更新されるのなら、

進捗の確認としても許せる気がします。

 

マクロとしては

ステータスバーに表示する時に、

「前に表示した時刻との差がY秒を超えていれば表示する」、

ということにすればよいことになります。

空文字を引数にするとステータスバーの表示をリセットするようにもするとよさそうです。

 

以上から、プロシジャー Function StbMsg を作りました。

main3のように呼び出して使います。

 

こころの相談室おうみ / 小倉

 

Function StbMsg(Optional msg As Variant = "", Optional sec As Double = 0.5) As Variant
    Static LastTimer As Double
    Dim NowTimer As Double
    With Application
        If msg <> "" Then
            NowTimer = Timer
            If Abs(LastTimer - NowTimer) >= sec Then
                .StatusBar = msg
                LastTimer = NowTimer
            End If
        Else
            .StatusBar = False
        End If
        StbMsg = .StatusBar
    End With
End Function

 

 

 

 

 

●ステータスバーに何かを表示するのにかかる時間

1.ループを100万回まわすと、0.00390625 秒でした(main1)。

2.ステータスバーに100回表示させると、0.1953125 秒でした(main2)。

3.よってステータスバーに一回表示させると、2ミリ秒(0.00195=0.1953125/100 - 0.0039/1000000)かかります。

 

 

 

Sub main1()
    Dim i As Long, n As Long
    Dim t1 As Double, t2 As Double
    n = 1000000
    t1 = Timer
    For i = 1 To n
        '何もしない
    Next i
    t2 = Timer
    Debug.Print t2 - t1
End Sub

 

Sub main2()
    Dim i As Long, n As Long
    Dim t1 As Double, t2 As Double
    n = 100
    t1 = Timer
    For i = 1 To n
        Application.StatusBar = i & "/" & n
    Next i
    Application.StatusBar = False
    t2 = Timer
    Debug.Print t2 - t1
End Sub

 

Sub main3()
    Dim i As Long, n As Long
    Dim t1 As Double, t2 As Double
    n = 1000000
    t1 = Timer
    For i = 1 To n
        StbMsg i & "/" & n, 0.8
    Next i
    StbMsg
    t2 = Timer
    Debug.Print t2 - t1
End Sub