今日はVBAのお話です。
昨日、こんなツイートをしました。
ちょっと面白い挙動をするExcelマクロ。
セルA1をクリックするたびループが走ったり止まったりします。 pic.twitter.com/LWvJzVU0Ae— 佐藤嘉浩(Excelの魔法使い・スピルのひと) (@yosatonet) 2019年4月2日
これ、一見、なんでもないような、わりと簡単にできることのような感じがします。
セルA1をクリックするたびに動作が止まるというループを繰り返しているだけなのですが。
これってVBAではよく考えないとできないことなんです。
どこができないのか
今回のポイントは、繰り返しのループ動作になっているのですが、VBAって動作中は他の入力を受け付けてくれないはずです。
VBAはいったん動き出したら最後、全部処理が終わるか、強制終了する以外の方法で、他の入力を受け付けることはできません。
それができているのが今回のポイントです。
動作中に入力を受け付けているからくり
実は、今回、OnTimeというイベントを使っています。
これは、今から設定した時間に指定したマクロを動かすというイベントです。
勘のいい方は気付きましたでしょうか。
実は、今回、ループ処理していないのです。
マクロをスタートしたら、1秒後に自分自身のマクロを実行するように設定する、その繰り返しなのです。
すると、1秒ごとに、現在時刻を表示し、マクロ自身を実行するように設定するマクロが動くようになります。
その動作は一瞬で終わるので、それ以外の時間は入力を受け付けてくれます。
その受付時間内にセルA1をクリックすると、開始、停止が切り替わるように設定できるような、SelectionChangeイベントを仕込んでいます。この処理も一瞬で行われます。
実際のVBA
シートには以下のVBAが入っています。これでセルA1をクリックするたびにstart、stopを切り替えています。
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Address = “$A$1” Then
If Range(“A1”).Value = “stop” Then
Range(“A1”).Value = “start”
Else
Range(“A1”).Value = “stop”
Application.OnTime Now() + TimeValue(“00:00:01”), “経過時間”
End If
End If
End Sub
モジュールには以下のVBAが入っています。これはセルA1の値を見て、startならセルB2に時間を描き込むようにしています。
Sub 経過時間()
If Range(“A1”).Value = “stop” Then
Range(“B2”).Value = Now
Application.OnTime Now() + TimeValue(“00:00:01”), “経過時間”
End If
End Sub
シートに記録されている方も、モジュール内の方も、「Application.OnTime Now() + TimeValue(“00:00:01”), “経過時間”」という形でOnTimeイベントを記述しています。
シートの方はstart状態になったとき、モジュールの方はスタート状態の場合でセルB2に現在時刻を描き込んだ後に設定するようにしています。
OnTimeイベントの使い方
前にも説明した通り、OnTimeイベントは、指定した時間にそのイベントを発生させるイベントです。
書式は
Application.OnTime 時間,動作するマクロ名
です。
時間は、
TimeValue(“00:00:01”)
という時、分、秒という形で指定します。
今回は、今から指定した時間(1秒)後という指定の方法をするので、今の時間+指定した時間とするため、
Now() + TimeValue(“00:00:01”)
としています。
今回のような使い方をする場合は、Now() + TimeValueで指定します。
時刻アラームみたいな処理をする場合は、Now() +は付けないということで覚えておきましょう。
まとめ
ちなみに今回、シートにはセルB1に次の計算式を入力してありました。
=IF(A1=”start”,”■”,”➡”)
さらに、セルA1の文字色は白にして見えないようにしました。
だからこんな不思議な見た目が出来上がったのですね。
今回のような、動作中に入力や別の動作を差し込むことを「割り込み」と呼びます。
今回は厳密にいうと割り込みではなく、一回一回処理を終わらせ、自動起動するというものでしたが。
「割り込み」を発生させるには、今回のような方法のほかに、割り込みさせるイベントそのものである「DoEvents」というものもあります。
もしかすると「DoEvents」の方が簡単に設定できるかもしれないのですが、いつもうまくいかないというか苦手なのであまり私は使いません。
どなたか詳しい方はぜひ実働するものの記事化をどうぞよろしくお願いいたします。
コメント