t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

Static変数を利用してステータスバーに文字をスクロールさせる。

今回はExcelのステータスバーに電光掲示板のように文字をスクロールさせるマクロを紹介。
もともと作りたかった案件とは違うが、そちらが失敗して副産物として単体で何か使えそうな気がしたので簡単にメモ。

矢印の方向に文字が流れる。
f:id:t-hom:20180527132653p:plain

コード

※Mainプロシージャを起動すると無限ループになるので止め方をご存知の方のみ実行してください。

#If VBA7 Then
    Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal ms As LongPtr)
#Else
    Private Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
#End If

Sub Main()
    Do
        Application.StatusBar = RotateString("ただいまマクロを実行しています。しばらくお待ちください。", " ")
        DoEvents
        Sleep 100
    Loop
End Sub

Private Function RotateString(cap As String, pad As String)
    Dim paddedString As String
    paddedString = String(Len(cap), pad) & cap & String(Len(cap), pad)
    Static i As Long
    If Len(cap) * 2 > i Then
        i = i + 1
    Else
        i = 1
    End If
    RotateString = Mid(paddedString, i, Len(cap))
End Function

解説

RotateString関数のStatic変数 i がポイント。
Staticで宣言した変数はプロシージャが終了しても値が保持されるので、このように呼び出すたびに違う値を返す関数を作るのに便利だ。

Staticを使いこなすコツは、「明示的に初期化しない」こと。

たとえば以下の箇所は、宣言された後、値が代入される前にIf文の判定でiを参照している。

    Static i As Long
    If Len(cap) * 2 > i Then
        i = i + 1
    Else
        i = 1
    End If

Long型で宣言したなら初期値は0なので、初回の呼び出し時にiは0である。
2度目の呼び出し時には、iは前回の呼び出しの終了時点の値をキープしている。

もし以下のように0で初期化する処理を挟んでしまうと何度呼び出しても0が入ってしまい、Staticにした意味がなくなる。

    Static i As Long
    i = 0
    If Len(cap) * 2 > i Then
        i = i + 1
    Else
        i = 1
    End If

明示的に代入する前に参照させるのがStaticを使いこなすコツだ。
これは慣れるまでなんとなく気持ち悪いかもしれないが、そういうものだと割り切るしかない。

関数のおおまかな処理

(1) まず、引き渡された文字列に、それと同じ長さの詰め物を両サイドに敷き詰める。
詰め物 & "サンプル" & 詰め物
      ↓こうなる
"□□□□サンプル□□□□"

(2) iが文字列の長さの2倍未満なら、iを増分させる。
初回は0なので、iが1になる。

(3) iの値の位置から元の文字列と同じ長さを切り出す。
"□□□□"となる。

2回目の実行ではiが増えているので、"□□□サ"、3回目は"□□サン"という風に、切り出す位置を変えているだけ。

以上

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