2023/05/01

OnTimeメソッドの第一・第二パラメータ設定方法




ある指定時刻にマクロを実行したい場合や、何らかの原因でVBAの実行が中断してしまう時に流れを復活させる場合には「Application.OnTime」メソッドを使います。
OnTimeには以下のように4つのパラメータを指定します。第一パラメータ「EarliestTime:実行時刻」と第二パラメータ「Procedure:実行プロシージャ名」は必須です。
Application.OnTime (EarliestTime, Procedure, [LatestTime,] [Schedule])

今回はOnTimeの基本的な使い方に加え、ミリ秒単位の時刻設定方法、実行プロシージャの引数の指定方法、および標準モジュール以外の実行プロシージャ指定方法などについて紹介します。
(第三・第四パラメータについては、今回全く触れていません。了承下さい。)

なお、ここではOnTimeメソッドがあるプロシージャを「予約プロシージャ」、OnTimeメソッドの第二引数に指定され、時間が来た時に実行されるプロシージャを「実行プロシージャ」と呼び分ける事にします。

1.第一パラメータ(実行時刻)指定方法

1ー1.絶対日時を指定

第一パラメータの実行時刻には、Date型の(日付+)時刻を指定します。

まず「TimeValue("12:34:56")」のように設定するとします。TimeValue("12:34:56")で得られる値は「0.5242・・・」という「1未満」の値です。
この場合、現在の時刻(≒第一パラメータを監視している時刻)は、同じ1未満の値(=Time関数で得られる値)になっているようです。そして実行プロシージャが実行されるのは「次の12時34分56秒」という事になります。
つまり予約をした時刻が12時34分56秒より前であれば、その日の12時34分56秒に実行されますが、過ぎた時刻に予約をすれば「(たぶん)次の日の12時34分56秒」に実行される事になります。

一方「DateValue("2023/4/1") + TimeValue("12:34:56")」のように設定すると、得られる値は「45017.5242・・・」という「1以上」の値となります。下の相対日時を指定で説明する「Now() + TimeValue("0:00:02")」のような設定でも同じです。
この場合の現在時刻(≒第一パラメータを監視している時刻)は、1以上の値(Now関数で得られる値)になっているようで、実行プロシージャが実行されるのは2023年4月1日の12時34分56秒です。
もし2023年4月1日の12時34分56秒を過ぎてから予約をした場合は、「即座に実行」されることになります。次にその日その時刻が回ってくるまで実行されない・・なんていう事はありません(と言うか、二度と回ってきません)。

なお、予約情報は「OnTimeメソッドを実行したExcel本体」で管理しているようで、予約したブックを閉じてしまっても時間が来たら勝手にファイルを起動し、実行プロシージャを実行してくれます。
逆に、遠い先の日付・時刻を設定してしまうと、Excelは閉じずに「立ち上げ続けておく」必要があるので、運用する上では注意が必要です。

1ー2.相対日時を指定

「今から何分後」や「今から何秒後」のように設定する場合は、現時刻を「Now()」関数で取得し、その時刻に対してTimeValue関数で「経過時間」を指定します。例えば10秒後なら「Now() + TimeValue("0:00:10")」とします。
また、Excelでは1日が「1」ですので、1秒は「1 ÷ 24(時間) ÷ 60(分) ÷ 60(秒)」で表せます(小数点で表すと、0.00001157・・・)。ですので、前述「TimeValue("0:00:10")」の代わりに「10 / (24 * 60 * 60)」や「10 / 86400」という数式を使用してもOKです。

1ー3.ミリ秒単位での指定

なおOnTimeメソッドの精度は、Microsoftでも「秒単位」と説明しています。
しかし「[Now() + TimeValue("0:00:01.50")]」のように実行日時値の両端を角カッコで囲むことで、ミリ秒での制御(この場合1.5秒後にプロシージャ実行)が出来るようです。(バージョンにより可不可があるかもしれません。)
角カッコはEvaluateメソッドと同等の機能を表す記号なので、Evaluate("Now() + TimeValue(""0:00:01.50"")")でも同じです(Evaluateの引数は文字列にする必要があるので、TimeValue内で使用している記号のダブルクォーテーションは、文字列としてのダブルクォーテーションとするために「二重」にしています)。

精度を確認するため、例えば「2秒後」の設定を「秒単位で呼び出し」た時と、「角カッコ(Evaluate)を使用」した時とで比較すると、以下の様になりました(10回トライ)。
 秒単位 :1.05~2.00秒(平均1.56秒)
 角カッコ:2.00~2.10秒(平均2.03秒)
秒単位の場合は、キリの良い秒単位時刻の時に予約プロシージャが実行されますので「平均は1.5秒」という予想通りになります。これに対し角カッコを使用すると、ミリ秒単位で時間を測り、予約時刻(この場合は2秒後)になってから予約プロシージャを起動する という動きのようです。時間精度的には角カッコ付きの方が良さそうです。

2.第二パラメータ(実行プロシージャ)指定方法

第一パラメータでの指定時間に実行される実行プロシージャ名は、文字列の形で指定します。

2ー1.引数が無い時

実行プロシージャに対して、引数を付けない場合は、単純に「プロシージャ名を文字列で指定(両端をダブルクォーテーションで囲む)」します。なお、実行プロシージャ側の引数が全てOptionalの省略可能で、且つ予約側からは引数を渡さない場合も、この「引数無し」の状態に当てはまります。

例えば、実行プロシージャ名を「Exec01」とし、2秒後に実行しようとすると図01のようにします。
  1. '========== ⇩(1) 予約プロシージャ ============
  2. Sub Call_01()
  3.  Application.OnTime Now() + TimeValue("0:00:02"), "Exec01"
  4. End Sub
  5. '========== ⇩(2) 実行プロシージャ ============
  6. Public Sub Exec01()
  7.  MsgBox "Hello World"
  8. End Sub
図01


02行目「Application.OnTime Now() + TimeValue("0:00:02"),"Exec01"」では、OnTimeメソッドの第二パラメータに、実行プロシージャを文字列で「"Exec01"」と指定しています。

2ー2.引数が有る時

2ー2ー1.直値での指定

引数がある時は、以下の様にします。
 プロシージャ名の後ろに「半角スペースを1つ」空けてから、第一引数を並べる
複数の引数がある場合には、引数間を「,(カンマ)」でつなぐ
文字列型の引数には、ダブルクォーテーションを二重に付ける(文字列としてのダブルクォーテーションにする)
プロシージャ名と全ての引数を囲むようにシングルクォーテーションを付ける
シングルクォーテーションの外側をダブルクォーテーションで囲む(OnTimeの第二パラメータ(文字列)にする)

例えば、プロシージャ名を「Exec02」とし、第一引数に「"ABC"(文字列)」第二引数に「123(数値)」を指定する時は、以下のようにします。
  1. '========== ⇩(3) 予約プロシージャ(引数がある場合) ============
  2. Sub Call_02()
  3.  Application.OnTime Now() + TimeValue("0:00:02"), "'Exec02 ""ABC"",123'"
  4. End Sub
  5. '========== ⇩(4) 実行プロシージャ ============
  6. Public Sub Exec02(S As String, L As Long)
  7.  MsgBox S & vbNewLine & L
  8. End Sub
図02


22行目「Application.OnTime Now() + TimeValue("0:00:02"), "'Exec02 ""ABC"",123'"」では、第二パラメータとして「"'Exec01 ""ABC"",123'"」を指定しています。これを詳細に説明しているのが図03です。
引数付きプロシージャ名の指定方法
図03


寄り道
なお、プロシージャ名の後ろの「半角スペースは必須」みたいな書き方をしていますが、実は半角スペースの無い
 「Application.OnTime Now() + TimeValue("0:00:02"), "'Exec02""ABC"",123'"」
でも動きます。これは、第二パラメータは「Exec01"ABC",123」という文字列と解釈され、「プロシージャと第一引数はダブルクォーテーションで区分けできる」ためのようです。

但しもし第一引数が数値型だった場合、プロシージャ名の後ろにスペースが無いと「"'Exec01123,""ABC""'" (赤字が第一引数)」となり、プロシージャ名が変ってしまうためにエラーになってしまいます。図04のような引数を省略できる場合でも、プロシージャ名のすぐ後ろにカンマがあるのも異常とみなされるようです。

第一引数を何のデータ型にするかは、場面場面で異なるでしょうから、常に「プロシージャ名の後ろにはスペースを入れる」としておいた方が安全だと思います。
(なお、数値も必ず「ダブルクォーテーション」で囲み、「引数は必ず文字列」と統一してしまえば、プロシージャ名の後ろのスペースは不要に出来そうです。しかし、コードの文字数としては「半角スペース1個 < ダブルクォーテーション 4個」で、半角スペースの方に軍配は上がりそうです。)

また、そのプロシージャの後ろの半角スペースは「全角スペース」でも大丈夫なようです。なお、これはOnTimeメソッド特有の現象で、一般的にはエラーになるのが普通だという認識です。
変数やプロシージャ名にも全角を使う方がいますが、間違いの元になるので、文字列の直値だけに留めておいた方が良いと思います。

2ー2ー2.省略可能な引数の場合

実行プロシージャ側の引数が全て省略可能(Optional引数)で、1つ目の引数を省略したい場合は、図04のように第一引数を省略します。
  1. '========== ⇩(5) 予約プロシージャ(引数を省略する場合) ============
  2. Sub Call_03()
  3.  Application.OnTime Now() + TimeValue("0:00:02"), "'Exec03 ,123'"
  4. End Sub
  5. '========== ⇩(6) 実行プロシージャ(省略可能な引数) ============
  6. Public Sub Exec03(Optional S As String = "DEF", Optional L As Long = 456)
  7.  MsgBox S & vbNewLine & L
  8. End Sub
図04


42行目「Application.OnTime Now() + TimeValue("0:00:02"), "'Exec03 ,123'"」のように、プロシージャ名(Exec03)の後ろの半角スペースの後ろに、すぐにカンマ」をすれば「1番目の引数は省略」したことになります。

2ー2ー3.変数での指定

上記では引数を直値(直接、値の形でコードに埋め込む)で使いましたが、実際には変数にすることが多いと思います。
図05は定数を渡していますが、変数と思って見て下さい。
  1. '========== ⇩(7) 予約プロシージャ(引数を変数で渡す) ============
  2. Sub Call_04()
  3.  Const S As String = "ABC"
  4.  Const L As Long = 123
  5.  Application.OnTime Now() + TimeValue("0:00:02"), "'Exec04 " & """" & S & """" & "," & L & "'"
  6. End Sub
  7. '========== ⇩(8) 実行プロシージャ ============
  8. Public Sub Exec04(S As String, L As Long)
  9.  MsgBox S & vbNewLine & L
  10. End Sub
図05


65行目「Application.OnTime Now() + TimeValue("0:00:02"), "'Exec04 " & """" & S & """" & "," & L & "'"」が変数(定数)を引数として渡すOnTimeメソッドの例ですが、ダブルクォーテーションとシングルクォーテーションが入り混じっていますので、図06で分解して説明します。

変数を引数に指定する場合
図06


文字列変数(ここではS)は、直値と同様に「ダブルクォーテーションを二重」にして囲む必要があります。図06ではダブルクォーテーションを「&」で繋いで独立させていますので、ダブルクォーテーションが4重になります。また最後のシングルクォーテーションも独立させていますので、「ダブルクォーテーション+シングルクォーテーション+ダブルクォーテーション」という文字列になります。
もちろん、プロシージャ名や引数間カンマとダブルクォーテーションを一緒にして、図07のようにしてもOKです。

変数を引数に指定する場合(単純化)
図07


但し複数種の記号を一緒にすると、何のダブルクォーテーションを何個並べたのかすぐ分からなくなるので、慣れるまでは図06の書き方をお勧めします。

2ー2ー4.日付を引数にする場合

日付値は数値なのですが、Date型で渡そうとするとうまくいきません。
例えば「2023/4/5」は「2023÷4÷5」という数式のような計算をし、その計算結果の値(101.15)を渡す事になります。送られた側はその「101.15という値」を日付に直し「1900/04/10 3:36:00 」と受け取ってしまいます。
ですので、日付はLong型(時刻も含む場合はDouble型)で渡すと良さそうです。
  1. '========== ⇩(9) 予約プロシージャ(引数=日付) ============
  2. Sub Call_05()
  3.  Const T As Long = #4/5/2023#
  4. ' Dim T As Long
  5. ' T = CLng(CDate("2023 / 4 / 5"))
  6.  Application.OnTime Now() + TimeValue("0:00:02"), "'exec05 " & T & "'"
  7. End Sub
  8. '========== ⇩(10) 実行プロシージャ(配列受け取り) ============
  9. Public Sub exec05(T as Date)
  10.  MsgBox T
  11. End Sub
図08


日付値は、82行目「Const T As Long = #4/5/2023#」のようにLong型にするか、見え消しの83~84行目のようにCLng関数で変換しておきます。
そして86行目「Application.OnTime Now() + TimeValue("0:00:02"), "'exec05 " & T & "'"」で、日付を数値(Long型)として渡します。

2ー2ー5.配列を引数にする場合

引数として配列を渡したい場合、配列を直接指定してしまうと「配列はString型では無い」のでエラーが発生します。
1つの方法として図09のように「配列を文字列」の形にして渡すと、受け取ってくれます。
  1. '========== ⇩(11) 予約プロシージャ(引数=配列) ============
  2. Sub Call_06()
  3.  Const A As String = "Array(2, 3)"
  4.  Application.OnTime Now() + TimeValue("0:00:02"), "'exec06 " & A & "'"
  5. End Sub
  6. '========== ⇩(12) 実行プロシージャ(配列受け取り) ============
  7. Public Sub exec06(A as Variant)
  8.  MsgBox A(0) & vbNewLine & A(1)
  9. End Sub
図09


もし要素数が固定ならば、実行プロシージャ側に要素数の数だけ引数を設け、1要素ずつ渡すのも1つの手だと思います。

2ー2ー6.オブジェクトを引数にする場合

オブジェクトを渡すことも可能です。図10では、セル範囲を渡しています。
  1. '========== ⇩(13) 予約プロシージャ(引数=オブジェクト風の文字列) ============
  2. Sub Call_07()
  3.  Const R As String = "Range(""A1"")"
  4.  Application.OnTime Now() + TimeValue("0:00:02"), "'exec07 " & R & "'"
  5. End Sub
  6. '========== ⇩(14) 実行プロシージャ(オブジェクト受け取り) ============
  7. Public Sub exec07(R as Range)
  8.  MsgBox R.Value
  9. End Sub
図10


122行目「Const R As String = "Range(""A1"")"」では、セル範囲である「Range("A1")」をそのまま文字列にしています。カッコ内のダブルクォーテーションは文字列にするために二重にしています。
その文字列変数(定数)Rを124行目「Application.OnTime Now() + TimeValue("0:00:02"), "'exec07 " & R & "'"」で引数に指定しています。
受け取る側は128行目「Public Sub exec04(R as Range)」のように、Rangeオブジェクトとして引数を受け取れます。

ちょっと無理矢理の手法ですが、「文字列」か「数値」の状態にできさえすれば、受け取り側で「元のデータ型」で処理できそうです。但し、特にオブジェクトの場合は、うまくいかないものの方が多いとは思います。

2ー2ー7.引数をカッコで囲む方法

今までは、OnTimeメソッドの第二パラメータとして「プロシージャ名+半角スペース+第一引数 [+カンマ+第二引数+・・・] 」という構文を紹介しました。
別な方法として、図11のように「引数をカッコで囲う」方法でもOKです。カッコを使う場合は、プロシージャ名と第一引数の間には「半角スペースを入れなくても良い」です。
  1. '========== ⇩(15) 予約プロシージャ(引数をカッコで囲む方法) ============
  2. Sub Call_08()
  3.  Const S As String = "ABC"
  4.  Const L As Long = 123
  5.  Application.OnTime Now() + TimeValue("0:00:02"), "'Exec08" & "(""" & S & """)" & "," & "(" & L & ")'"
  6. End Sub
  7. '========== ⇩(16) 実行プロシージャ ============
  8. Public Sub Exec08(S as String, L as Long)
  9.  MsgBox S & vbNewLine & L
  10. End Sub
図11


145行目「Application.OnTime Now() + TimeValue("0:00:02"), "'Exec08" & "(""" & S & """)" & "," & "(" & L & ")'"」では、各引数をカッコで囲みます。分解すると図12のようになります。
引数をカッコで囲む
図12


このカッコ書き方式だと、第二パラメータとしては「Exec08("ABC"),(123)」という形になります。これをVBA関数のように「Exec08("ABC",123)」と引数をカッコ内にまとめたような書き方をすると、エラーが発生します。
なおプロシージャ名と左カッコの間に、半角スペースが入っていても動きますし、また「カッコ有りとカッコ無しの混在」もOKです。例えば第二パラメータが 「"'Exec08" & "(""" & S & """)" & "," & L & "'"」や「"'Exec08" & """" & S & """" & "," & "(" & L & ")'"」も大丈夫です。
但し、第一引数が数値の時にカッコを取ってしまうと、プロシージャ名の後ろにスペースが無いと「プロシージャ名と第一引数の数値がくっついてしまう」のでエラーとなります。

3.実行プロシージャが他ブックにある場合

3ー1.同じフォルダー内に呼び出すブックがある場合

上記(実行プロシージャ指定方法)は、実行プロシージャが「同じブック内」に存在する時を説明してきました。実行プロシージャが異なるブックにある場合には「拡張子を含んだブック名+!(クエスチョンマーク)」をプロシージャ名の前に付けます。
図13では、同じフォルダー内に「its-037A.xlsm」というブックがあり、そこに「Exec09」や「Exec10(S As String, L As Long)」の実行プロシージャがあると仮定しています。
  1. '========== ⇩(17) 予約プロシージャ(引数無しの他ブックの呼び出し) ============
  2. Sub Call_09()
  3.  Application.OnTime Now() + TimeValue("0:00:02"), "its-037A.xlsm!Exec09"
  4. End Sub
  5. '========== ⇩(18) 予約プロシージャ(引数有りの他ブックの呼び出し) ============
  6. Sub Call_10()
  7.  Const S As String = "ABC"
  8.  Const L As Long = 123
  9.  Application.OnTime Now() + TimeValue("0:00:02"), "its-037A.xlsm!'Exec10 """ & S & """," & L & "'"
図13


この場合、170行目「Application.OnTime Now() + TimeValue("0:00:02"), "its-037A.xlsm!'Exec10 """ & S & """," & L & "'"」では、引数を含む第二パラメータを囲んでいる「シングルクォーテーション」を「プロシージャ名+引数を囲む」ように付けています。別な言い方をすれば「ブック名+!(クエスチョンマーク)は、シングルクォーテーションの外側」になります。

3ー2.異なるフォルダー内に呼び出すブックがある場合

上記の「異なるブック」は「同じフォルダーに置いてあるブック」です。呼び出すブックがOnTimeを実行するブックと異なる場所にある場合は、図14のようにブック名の前にパスを付けます。
図14では、「C:¥Data」というフォルダーに「its-037A.xlsm」というブックがあり、そこに「Exec11」や「Exec12(S As String, L As Long)」の実行プロシージャがあると仮定しています。
  1. '========== ⇩(19) 予約プロシージャ(引数無しの他ブックの呼び出し) ============
  2. Sub Call_11()
  3.  Application.OnTime Now() + TimeValue("0:00:02"), "C:¥Data¥its-037A.xlsm!Exec11"
  4. End Sub
  5. '========== ⇩(20) 予約プロシージャ(引数有りの他ブックの呼び出し) ============
  6. Sub Call_12()
  7.  Const S As String = "ABC"
  8.  Const L As Long = 123
  9.  Application.OnTime Now() + TimeValue("0:00:02"), "C:¥Data¥its-037A.xlsm!'Exec12 """ & S & """," & L & "'"
図14


182行目では、第二パラメータは「"C:¥Data¥its-037A.xlsm!Exec11"」のように、クエスチョンマークの前部分に「C:¥Data¥its-037A.xlsm」と「フルパス+ブック名」を指定します。
もし、相対的パスで表したい時は「ThisWorkbook.Path & "¥..¥Data¥its-037A.xlsm!Exec11"」のように、予約プロシージャのブック位置を「ThisWorkbook.Path」とし、その後ろ側に相対的なフォルダの位置+ブック名を続けます。

4.モジュールオブジェクト名を指定した実行プロシージャ

技術的な話になりますが、実行プロシージャを置いたモジュールの「オブジェクト名」を実行プロシージャ名の前につける事で、標準モジュールでは無くシートモジュールやブックモジュールに置いた実行プロシージャも呼び出すことが可能です。
しかも、Privateプロシージャも呼び出すことが可能となります。

4ー1.書式

例えば、引数が無い場合は以下の様に「実行プロシージャ名の前に、所属するモジュールオブジェクト名を追加」します。
 「Application.OnTime Now() + TimeValue("0:00:02"), "Sheet1.Exec01"」

引数がある場合も、図15のように「モジュールオブジェクト名を付けた実行プロシージャ名」とします。

引数付きプロシージャ名の指定方法(モジュールのオブジェクト名を付ける時)
図15


なお引数がある場合、プロシージャ名+引数を囲っていたシングルクォーテーションは「オブジェクト名も含めた範囲を囲む」ことが必要です。

4ー2.指定の考え方

OnTimeメソッドで呼び出す実行プロシージャは、一般的には「標準モジュール」に置かれ、且つ「Public」プロシージャにすることが多いと思います。その場合は、上記で示してきたように「実行プロシージャ名のみ」で呼び出せます。

と言って、標準モジュール以外に置かれたプロシージャや、Privateプロシージャが呼び出せない訳でもありません。
結論を先に言うと、実行プロシージャ名の前に「所属のモジュールオブジェクト名」を付けると、「標準モジュールで無くても、またPrivateプロシージャでも」OnTimeメソッドで呼び出す事ができます。

まず、予約プロシージャ側・実行プロシージャ側で、何の要素がオブジェクト名の指定要否を決めているのかですが、図16のように「呼び出す側の場所」「呼び出される側の場所」「呼び出す時に引数を付けているか」「呼び出されるプロシージャがPublicかPrivateか」の4要素が関係しているようです。
場所その他
予約プロシージャ側Module / Sheet / ThisWorkbook / UserForm引数の有無
実行プロシージャ側Module / Sheet / ThisWorkbookPublic or Private
図16


この4要素を振って確認した結果が図17です。なお「サンプルファイル」では、この組合せの確認が可能です。
実行プロシージャ
ModuleSheetThisWorkbook
PublicPrivatePublicPrivatePublicPrivate







Module引数無
引数有
Sheet引数無
引数有
ThisWorkbook引数無
引数有
UserForm引数無
引数有
〇=プロシージャ名のみでOK
●=モジュールオブジェクトの指定要 
図17


まず、実行プロシージャがシートモジュールに置かれている場合は、OnTimeメソッドの第二パラメータ(実行プロシージャ名)に、シートモジュールのオブジェクトを指定する必要があります。例えば「Sheet1」にある「Exec13」というプロシージャを呼び出す場合は、

Application.OnTime Now() + TimeValue("0:00:02"), "'Sheet1.Exec13 """ & S & """," & L & "'"

と、プロシージャ名の前に、所属を示す「Sheet1.」を付け加えます。もし引数がある場合なら、プロシージャと引数をセットにするシングルクォーテーションは「Sheet1も含めて囲む」ように付けます。
なおシートモジュールの場合は、実行プロシージャがPublicであっても、Privateであっても同じです。

実行プロシージャがブックモジュールに置かれている場合も同様に、プロシージャ名の前に所属を示す「ThisWorkbook.」を付け加えて、以下のように記述します。

Application.OnTime Now() + TimeValue("0:00:02"), "'ThisWorkbook.Exec14 """ & S & """," & L & "'"

次に、実行プロシージャが標準モジュール(例えばModule1)に置かれている場合は、ちょっと複雑です。
「実行プロシージャがPrivate」且つ「OnTimeメソッドの第二引数に引数が有る」場合には、以下のように「Module1.」を付け加えることで、実行プロシージャがPrivateであっても実行できます。

Application.OnTime Now() + TimeValue("0:00:02"), "'Module1.Exec15 """ & S & """," & L & "'"

なお、標準モジュールのオブジェクト名(例:Module1)をPublicの実行プロシージャ名に付けても、特に害は無さそうです。

また、ユーザーフォームのフォームモジュール内に実行プロシージャを置いた場合も試してみたのですが、どこからもうまく呼び出せなかったため、図17の横軸には加えませんでした。逆にフォームモジュール内からは呼び出すことが可能です。

5.ツールの説明

今回のツール(サンプルファイル)は、ボタンをクリックするとメッセージボックスが出るだけのものです。特に面白い機能が盛り込まれている訳でも無いので、興味のある方以外は無視しても問題ないと思います。

5ー1.ツール概要

サンプルファイルのSheet1上にボタンを36+2個ならべています(図18)。
ツールの画面
図18


ボタン1~12は標準モジュール上に置いた予約プロシージャを実行するものであり、その内ボタン1~6は引数無し、ボタン7~12は引数有りとなっています。またボタン1~2は実行プロシージャが標準モジュールにあり、ボタン1がPublic・ボタン2がPrivateにしています。同様にボタン3~4がシートモジュール上に実行プロシージャを置き、ボタン5~6がブックモジュールに実行プロシージャを置いています。

また同様に、ボタン13~24がシートモジュールに予約プロシージャを置き、ボタン25~36がブックモジュールに予約プロシージャを置いています。

一番下の「Modal」と「Modeless」ボタンは、ユーザーフォームを起動し、そのフォーム上にシート上と同様のボタン「CB37~48」を配置しています。
なお「Modalボタン」はフォームをモーダルで、「Modelessボタン」はモードレスでフォームを起動しますが、フォーム起動状態によるOnTimeの動作は特に違いは無いようです。

ボタンをクリックした時には、1秒後(標準仕様の秒単位制御にしていますので、正確には0~1秒後)に図19のようなメッセージボックスが表示されます。
サンプルファイルのボタンクリック時の出力
図19


メッセージボックスは3段で文字列が出力され、1段目は「実行プロシージャの場所」と「実行プロシージャがPublicかPrivateか」を表示します。
2段目は「第一引数の値」で、値が123の場合は「予約プロシージャ側からの指定」、値が456の場合は「実行プロシージャの既定値(=実行プロシージャ側から第一引数を渡していない)」となります。
3段目は「第二引数の値」で、値が"ABC"の場合は「予約プロシージャ側からの指定」、値が"DEF"の場合は「実行プロシージャの既定値(=実行プロシージャ側から第二引数を渡していない)」と事を示します。

5ー2.ワークシート(Sheet1)

5ー2ー1.シート上のレイアウト

シート上には図20のように「6列 × 6行」のセル内に合計36個のボタン(フォームコントロール)を配置しています。各ボタンには「Call_S01」から始まる予約プロシージャをプロシージャの番号をボタンの番号と合わせる形でマクロ登録しています。

Call_S01 ~ Call_S12は標準モジュールに、Call_S13 ~ Call_S24はシートモジュールに、Call_S25 ~ Call_S36はブックモジュールに予約プロシージャを置いてあります。
シート上のレイアウト
図20


36個のボタンの下に、ユーザーフォームを起動するためのボタンを2個配置しています。Modalと書かれた左側のボタンには、標準モジュールに配置した「UF_modal」プロシージャを、Modelessと書かれた右側ボタンには「UF_modeless」プロシージャをマクロ登録しています。

なおボタン表面の文字色は手動設定です。図17でも示した表と同じで、赤色が標準モジュールのオブジェクト名を指定する必要があり、青色がシートモジュールのオブジェクト名、緑色がブックモジュールのオブジェクト名が指定必要であることを表しています。

5ー2-2.シートモジュール

まず、シートモジュール上に配置された実行プロシージャが図21です。
  1. '========== ⇩(21) シートモジュールの実行プロシージャ(Public) ============
  2. Public Sub Exec_S03(Optional L As Long = 456, Optional S As String = "DEF")
  3.  MsgBox "Sheet1/Public" & vbNewLine & L & vbNewLine & S
  4. End Sub
  5. '========== ⇩(22) シートモジュールの実行プロシージャ(Private) ============
  6. Private Sub Exec_S04(Optional L As Long = 456, Optional S As String = "DEF")
  7.  MsgBox "Sheet1/Private" & vbNewLine & L & vbNewLine & S
  8. End Sub
図21


201行目「Public Sub Exec_S03(Optional L As Long = 456, Optional S As String = "DEF")」はPublicプロシージャで、引数は有無を吸収するために全てOptional(省略可)としています。第一引数をLong型、第二引数をString型にしていて、今まで説明に使ってきた引数の順序と入れ替わっていますが他意はありません。

202行目「MsgBox "Sheet1/Public" & vbNewLine & L & vbNewLine & S」では受け取った引数値を使ってメッセージを出しています。
但し引数が省略された時には「第一引数=456」「第二引数="DEF"」となる(引数を指定した時は、図28で「第一引数=123」「第二引数="ABC"」に設定されている)ので、引数が渡されたか否かが分かるようにしています。

206~208行目は、内容は同じですがPrivateプロシージャとなっています。

以下の図22は、シート上のボタン(ボタン13~18)をクリックした時に呼び出されます。シートモジュールの予約プロシージャから「引数無し」で実行プロシージャを呼び出すものです。
  1. '========== ⇩(23) 予約プロシージャ(シート → 標準:Public+引数無し) ============
  2. Sub Call_S13()
  3.  Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S01"
  4. End Sub
  5. '========== ⇩(24) 予約プロシージャ(シート → 標準:Private+引数無し) ============
  6. Sub Call_S14()
  7.  Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S02"
  8. End Sub
  9. '========== ⇩(25) 予約プロシージャ(シート → シート:Public+引数無し) ============
  10. Sub Call_S15()
  11.  'Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S03"
  12.  Application.OnTime Now() + TimeValue("0:00:01"), "Sheet1.Exec_S03"
  13. End Sub
  14. '========== ⇩(26) 予約プロシージャ(シート → シート:Private+引数無し) ============
  15. Sub Call_S16()
  16. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S04"
  17.  Application.OnTime Now() + TimeValue("0:00:01"), "Sheet1.Exec_S04"
  18. End Sub
  19. '========== ⇩(27) 予約プロシージャ(シート → ブック:Public+引数無し) ============
  20. Sub Call_S17()
  21. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S05"
  22.  Application.OnTime Now() + TimeValue("0:00:01"), "ThisWorkbook.Exec_S05"
  23. End Sub
  24. '========== ⇩(28) 予約プロシージャ(シート → ブック:Private+引数無し) ============
  25. Sub Call_S18()
  26. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S06"
  27.  Application.OnTime Now() + TimeValue("0:00:01"), "ThisWorkbook.Exec_S06"
  28. End Sub
図22


例えば233行目「Application.OnTime Now() + TimeValue("0:00:01"), "Sheet1.Exec_S03"」は、図21のシートモジュール上の「Exec_S03」プロシージャを呼び出しています。しかし232行目で見え消しにしてある「Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S03"」では「シートオブジェクトの指定が無い」ために実行プロシージャが見つからず、図23のようなエラーが発生することになります。
プロシージャが見つからない時のエラー
図23


以下の図24は、シート上のボタン(ボタン19~24)をクリックした時に呼び出されます。シートモジュールの予約プロシージャから「引数有り」で実行プロシージャを呼び出すものです。
  1. '========== ⇩(29) 予約プロシージャ(シート → 標準:Public+引数有り) ============
  2. Sub Call_S19()
  3.  Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S01 " & L & "," & """" & S & """" & "'"
  4. End Sub
  5. '========== ⇩(30) 予約プロシージャ(シート → 標準:Private+引数有り) ============
  6. Sub Call_S20()
  7. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S02 " & L & "," & """" & S & """" & "'"
  8.  Application.OnTime Now() + TimeValue("0:00:01"), "'Module1.Exec_S02 " & L & "," & """" & S & """" & "'"
  9. End Sub
  10. '========== ⇩(31) 予約プロシージャ(シート → シート:Public+引数有り) ============
  11. Sub Call_S21()
  12. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S03 " & L & "," & """" & S & """" & "'"
  13.  Application.OnTime Now() + TimeValue("0:00:01"), "'Sheet1.Exec_S03 " & L & "," & """" & S & """" & "'"
  14. End Sub
  15. '========== ⇩(32) 予約プロシージャ(シート → シート:Private+引数有り) ============
  16. Sub Call_S22()
  17. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S04 " & L & "," & """" & S & """" & "'"
  18.  Application.OnTime Now() + TimeValue("0:00:01"), "'Sheet1.Exec_S04 " & L & "," & """" & S & """" & "'"
  19. End Sub
  20. '========== ⇩(33) 予約プロシージャ(シート → ブック:Public+引数有り) ============
  21. Sub Call_S23()
  22. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S05 " & L & "," & """" & S & """" & "'"
  23.  Application.OnTime Now() + TimeValue("0:00:01"), "'ThisWorkbook.Exec_S05 " & L & "," & """" & S & """" & "'"
  24. End Sub
  25. '========== ⇩(34) 予約プロシージャ(シート → ブック:Private+引数有り) ============
  26. Sub Call_S24()
  27. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S06 " & L & "," & """" & S & """" & "'"
  28.  Application.OnTime Now() + TimeValue("0:00:01"), "'ThisWorkbook.Exec_S06 " & L & "," & """" & S & """" & "'"
  29. End Sub
図24


例えば268行目「Application.OnTime Now() + TimeValue("0:00:01"), "'Module1.Exec_S02 " & L & "," & """" & S & """" & "'"」は、標準モジュールにある「Exec_S02」プロシージャ(図29)を呼び出しているものです。図22の227行目ではそのまま呼び出せていたものが、引数があるために「モジュールオブジェクト名(Module1.)」を付けないと呼び出せなくなります。

5ー3.ブックモジュール(ThisWorkbook)

ブックモジュール上に配置された実行プロシージャが図25です。301~303行目がPublicプロシージャで、306~308行目がPrivateプロシージャになります。
  1. '========== ⇩(35) ブックモジュールの実行プロシージャ(Public) ============
  2. Public Sub Exec_S05(Optional L As Long = 456, Optional S As String = "DEF")
  3.  MsgBox "book/Public" & vbNewLine & L & vbNewLine & S
  4. End Sub
  5. '========== ⇩(36) ブックモジュールの実行プロシージャ(Private) ============
  6. Private Sub Exec_S06(Optional L As Long = 456, Optional S As String = "DEF")
  7.  MsgBox "book/Private" & vbNewLine & L & vbNewLine & S
  8. End Sub
図25


以下の図26は、シート上のボタン(ボタン25~30)をクリックした時に呼び出されます。ブックモジュールの予約プロシージャから「引数無し」で実行プロシージャを呼び出すものです。
  1. '========== ⇩(37) 予約プロシージャ(ブック → 標準:Public+引数無し) ============
  2. Sub Call_S25()
  3.  Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S01"
  4. End Sub
  5. '========== ⇩(38) 予約プロシージャ(ブック → 標準:Private+引数無し) ============
  6. Sub Call_S26()
  7.  Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S02"
  8. End Sub
  9. '========== ⇩(39) 予約プロシージャ(ブック → シート:Public+引数無し) ============
  10. Sub Call_S27()
  11. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S03"
  12.  Application.OnTime Now() + TimeValue("0:00:01"), "Sheet1.Exec_S03"
  13. End Sub
  14. '========== ⇩(40) 予約プロシージャ(ブック → シート:Private+引数無し) ============
  15. Sub Call_S28()
  16. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S04"
  17.  Application.OnTime Now() + TimeValue("0:00:01"), "Sheet1.Exec_S04"
  18. End Sub
  19. '========== ⇩(41) 予約プロシージャ(ブック → ブック:Public+引数無し) ============
  20. Sub Call_S29()
  21. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S05"
  22.  Application.OnTime Now() + TimeValue("0:00:01"), "ThisWorkbook.Exec_S05"
  23. End Sub
  24. '========== ⇩(42) 予約プロシージャ(ブック → ブック:Private+引数無し) ============
  25. Sub Call_S30()
  26. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S06"
  27.  Application.OnTime Now() + TimeValue("0:00:01"), "ThisWorkbook.Exec_S06"
  28. End Sub
図26


以下の図27は、シート上のボタン(ボタン31~36)をクリックした時に呼び出されます。ブックモジュールの予約プロシージャから「引数有り」で実行プロシージャを呼び出すものです。
  1. '========== ⇩(43) 予約プロシージャ(ブック → 標準:Public+引数有り) ============
  2. Sub Call_S31()
  3.  Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S01 " & L & "," & """" & S & """" & "'"
  4. End Sub
  5. '========== ⇩(44) 予約プロシージャ(ブック → 標準:Private+引数有り) ============
  6. Sub Call_S32()
  7. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S02 " & L & "," & """" & S & """" & "'"
  8.  Application.OnTime Now() + TimeValue("0:00:01"), "'Module1.Exec_S02 " & L & "," & """" & S & """" & "'"
  9. End Sub
  10. '========== ⇩(45) 予約プロシージャ(ブック → シート:Public+引数有り) ============
  11. Sub Call_S33()
  12. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S03 " & L & "," & """" & S & """" & "'"
  13.  Application.OnTime Now() + TimeValue("0:00:01"), "'Sheet1.Exec_S03 " & L & "," & """" & S & """" & "'"
  14. End Sub
  15. '========== ⇩(46) 予約プロシージャ(ブック → シート:Private+引数有り) ============
  16. Sub Call_S34()
  17. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S04 " & L & "," & """" & S & """" & "'"
  18.  Application.OnTime Now() + TimeValue("0:00:01"), "'Sheet1.Exec_S04 " & L & "," & """" & S & """" & "'"
  19. End Sub
  20. '========== ⇩(47) 予約プロシージャ(ブック → ブック:Public+引数有り) ============
  21. Sub Call_S35()
  22. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S05 " & L & "," & """" & S & """" & "'"
  23.  Application.OnTime Now() + TimeValue("0:00:01"), "'ThisWorkbook.Exec_S05 " & L & "," & """" & S & """" & "'"
  24. End Sub
  25. '========== ⇩(48) 予約プロシージャ(ブック → ブック:Private+引数有り) ============
  26. Sub Call_S36()
  27. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S06 " & L & "," & """" & S & """" & "'"
  28.  Application.OnTime Now() + TimeValue("0:00:01"), "'ThisWorkbook.Exec_S06 " & L & "," & """" & S & """" & "'"
  29. End Sub
図27


5ー4.標準モジュール(Module1)

標準モジュールの先頭部で、システム内で共有して使用する「OnTimeメソッドの実行プロシージャの引数値」を図28のように設定します。
  1. '========== ⇩(49) 標準モジュールの実行プロシージャ(Public) ============
  2. Public Const L As Long = 123
  3. Public Const S As String = "ABC"
図28


401行目「Public Const L As Long = 123」では第一引数の値を、402行目「Public Const S As String = "ABC"」では第二引数の値を設定しています。この値を、各モジュールに置いた実行プロシージャの既定値(第一引数=456、第二引数="DEF")と置き換えることで、引数が渡っているか否かを知ることが出来ます。

標準モジュール上に配置された実行プロシージャが図29です。411~413行目がPublicプロシージャで、416~418行目がPrivateプロシージャになります。
  1. '========== ⇩(50) 標準モジュールの実行プロシージャ(Public) ============
  2. Public Sub Exec_S01(Optional L As Long = 456, Optional S As String = "DEF")
  3.  MsgBox "Module1/Public" & vbNewLine & L & vbNewLine & S
  4. End Sub
  5. '========== ⇩(51) 標準モジュールの実行プロシージャ(Private) ============
  6. Private Sub Exec_S02(Optional L As Long = 456, Optional S As String = "DEF")
  7.  MsgBox "Module1/Private" & vbNewLine & L & vbNewLine & S
  8. End Sub
図29


以下の図30は、シート上のボタン(ボタン1~6)をクリックした時に呼び出されます。標準モジュールの予約プロシージャから「引数無し」で実行プロシージャを呼び出すものです。
  1. '========== ⇩(52) 予約プロシージャ(標準 → 標準:Public+引数無し) ============
  2. Sub Call_S01()
  3.  Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S01"
  4. End Sub
  5. '========== ⇩(53) 予約プロシージャ(標準 → 標準:Private+引数無し) ============
  6. Sub Call_S02()
  7.  Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S02"
  8. End Sub
  9. '========== ⇩(54) 予約プロシージャ(標準 → シート:Public+引数無し) ============
  10. Sub Call_S03()
  11. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S03"
  12.  Application.OnTime Now() + TimeValue("0:00:01"), "Sheet1.Exec_S03"
  13. End Sub
  14. '========== ⇩(55) 予約プロシージャ(標準 → シート:Private+引数無し) ============
  15. Sub Call_S04()
  16. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S04"
  17.  Application.OnTime Now() + TimeValue("0:00:01"), "Sheet1.Exec_S04"
  18. End Sub
  19. '========== ⇩(56) 予約プロシージャ(標準 → ブック:Public+引数無し) ============
  20. Sub Call_S05()
  21. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S05"
  22.  Application.OnTime Now() + TimeValue("0:00:01"), "ThisWorkbook.Exec_S05"
  23. End Sub
  24. '========== ⇩(57) 予約プロシージャ(標準 → ブック:Private+引数無し) ============
  25. Sub Call_S06()
  26. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S06"
  27.  Application.OnTime Now() + TimeValue("0:00:01"), "ThisWorkbook.Exec_S06"
  28. End Sub
図30


以下の図31は、シート上のボタン(ボタン7~12)をクリックした時に呼び出されます。標準モジュールの予約プロシージャから「引数有り」で実行プロシージャを呼び出すものです。
  1. '========== ⇩(58) 予約プロシージャ(標準 → 標準:Public+引数有り) ============
  2. Sub Call_S07()
  3.  Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S01 " & L & "," & """" & S & """" & "'"
  4. End Sub
  5. '========== ⇩(59) 予約プロシージャ(標準 → 標準:Private+引数有り) ============
  6. Sub Call_S08()
  7. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S02 " & L & "," & """" & S & """" & "'"
  8.  Application.OnTime Now() + TimeValue("0:00:01"), "'Module1.Exec_S02 " & L & "," & """" & S & """" & "'"
  9. End Sub
  10. '========== ⇩(60) 予約プロシージャ(標準 → シート:Public+引数有り) ============
  11. Sub Call_S09()
  12. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S03 " & L & "," & """" & S & """" & "'"
  13.  Application.OnTime Now() + TimeValue("0:00:01"), "'Sheet1.Exec_S03 " & L & "," & """" & S & """" & "'"
  14. End Sub
  15. '========== ⇩(61) 予約プロシージャ(標準 → シート:Private+引数有り) ============
  16. Sub Call_S10()
  17. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S04 " & L & "," & """" & S & """" & "'"
  18.  Application.OnTime Now() + TimeValue("0:00:01"), "'Sheet1.Exec_S04 " & L & "," & """" & S & """" & "'"
  19. End Sub
  20. '========== ⇩(62) 予約プロシージャ(標準 → ブック:Public+引数有り) ============
  21. Sub Call_S11()
  22. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S05 " & L & "," & """" & S & """" & "'"
  23.  Application.OnTime Now() + TimeValue("0:00:01"), "'ThisWorkbook.Exec_S05 " & L & "," & """" & S & """" & "'"
  24. End Sub
  25. '========== ⇩(63) 予約プロシージャ(標準 → ブック:Private+引数有り) ============
  26. Sub Call_S12()
  27. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S06 " & L & "," & """" & S & """" & "'"
  28.  Application.OnTime Now() + TimeValue("0:00:01"), "'ThisWorkbook.Exec_S06 " & L & "," & """" & S & """" & "'"
  29. End Sub
図31


シート上の「modal」と「modeless」のボタンをクリックした時に呼び出されるのが図32です。
  1. '========== ⇩(64) ユーザーフォームの起動(モーダル) ============
  2. Sub UF_modal()
  3.  UserForm1.Show vbModal
  4. End Sub
  5. '========== ⇩(65) ユーザーフォームの起動(モードレス) ============
  6. Sub UF_modeless()
  7.  UserForm1.Show vbModeless
  8. End Sub
図32


512行目「UserForm1.Show vbModal」ではフォームをモーダルで起動し、517行目「UserForm1.Show vbModeless」ではモードレスで起動しています。今回はOnTimeメソッドの設定の違いを調べていますが、これに関しては「モーダルでもモードレスでも差は見当たらない」ようです。

5ー5.ユーザーフォーム(UserForm1)

5ー5ー1.フォーム上のレイアウト

フォーム上には、図33の様にボタンを12個並べています。各ボタンのオブジェクト名は、シート上のボタンと連続番号になるように、CommandButton37~48と手動で変更しています。またボタン表面の文字列は適当に変更(「CB」はCommandButtonの略)し、ボタンのタイトルとしているLabelも適当に配置しています。
なお、ボタン表面の文字の色は、図34のInitializeイベントプロシージャ内で変更しています。
フォーム上のコントロールレイアウト
図33


5ー5ー2.フォームモジュール

フォーム起動時に実行されるのが図34です。ここでは各ボタンの文字色を、シート上のボタンと同様の色「赤色(標準モジュールオブジェクトの指定要)」「青色(シートモジュールオブジェクトの指定要)」「緑色(ブックモジュールオブジェクトの指定要)」にしています。
  1. '========== ⇩(66) ボタンの文字色設定 ============
  2. Private Sub UserForm_Initialize()
  3.  Me.CommandButton44.ForeColor = RGB(255, 0, 0)
  4.  Me.CommandButton39.ForeColor = RGB(0, 0, 255)
  5.  Me.CommandButton40.ForeColor = RGB(0, 0, 255)
  6.  Me.CommandButton45.ForeColor = RGB(0, 0, 255)
  7.  Me.CommandButton46.ForeColor = RGB(0, 0, 255)
  8.  Me.CommandButton41.ForeColor = RGB(0, 176, 80)
  9.  Me.CommandButton42.ForeColor = RGB(0, 176, 80)
  10.  Me.CommandButton47.ForeColor = RGB(0, 176, 80)
  11.  Me.CommandButton48.ForeColor = RGB(0, 176, 80)
  12. End Sub
図34


色は「RGB(255, 0, 0)」が赤色、「RGB(0, 0, 255)」が青色、「RGB(0, 176, 80)」が緑色になります。

以下の図35は、フォーム上のボタン(CB37~42)をクリックした時に呼び出されます。フォームモジュールの予約プロシージャから「引数無し」で実行プロシージャを呼び出すものです。
  1. '========== ⇩(67) 予約プロシージャ(フォーム → 標準:Public+引数無し) ============
  2. Private Sub CommandButton37_Click()
  3.  Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S01"
  4. End Sub
  5. '========== ⇩(68) 予約プロシージャ(フォーム → 標準:Private+引数無し) ============
  6. Private Sub CommandButton38_Click()
  7.  Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S02"
  8. End Sub
  9. '========== ⇩(69) 予約プロシージャ(フォーム → シート:Public+引数無し) ============
  10. Private Sub CommandButton39_Click()
  11. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S03"
  12.  Application.OnTime Now() + TimeValue("0:00:01"), "Sheet1.Exec_S03"
  13. End Sub
  14. '========== ⇩(70) 予約プロシージャ(フォーム → シート:Private+引数無し) ============
  15. Private Sub CommandButton40_Click()
  16. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S04"
  17.  Application.OnTime Now() + TimeValue("0:00:01"), "Sheet1.Exec_S04"
  18. End Sub
  19. '========== ⇩(71) 予約プロシージャ(フォーム → ブック:Public+引数無し) ============
  20. Private Sub CommandButton41_Click()
  21. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S05"
  22.  Application.OnTime Now() + TimeValue("0:00:01"), "ThisWorkbook.Exec_S05"
  23. End Sub
  24. '========== ⇩(72) 予約プロシージャ(フォーム → ブック:Private+引数無し) ============
  25. Private Sub CommandButton42_Click()
  26. ' Application.OnTime Now() + TimeValue("0:00:01"), "Exec_S06"
  27.  Application.OnTime Now() + TimeValue("0:00:01"), "ThisWorkbook.Exec_S06"
  28. End Sub
図35


以下の図36は、フォーム上のボタン(CB43~48)をクリックした時に呼び出されます。フォームモジュールの予約プロシージャから「引数有り」で実行プロシージャを呼び出すものです。
  1. '========== ⇩(73) 予約プロシージャ(フォーム → 標準:Public+引数有り) ============
  2. Private Sub CommandButton43_Click()
  3.  Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S01 " & L & "," & """" & S & """" & "'"
  4. End Sub
  5. '========== ⇩(74) 予約プロシージャ(フォーム → 標準:Private+引数有り) ============
  6. Private Sub CommandButton44_Click()
  7. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S02 " & L & "," & """" & S & """" & "'"
  8.  Application.OnTime Now() + TimeValue("0:00:01"), "'Module1.Exec_S02 " & L & "," & """" & S & """" & "'"
  9. End Sub
  10. '========== ⇩(75) 予約プロシージャ(フォーム → シート:Public+引数有り) ============
  11. Private Sub CommandButton45_Click()
  12. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S03 " & L & "," & """" & S & """" & "'"
  13.  Application.OnTime Now() + TimeValue("0:00:01"), "'Sheet1.Exec_S03 " & L & "," & """" & S & """" & "'"
  14. End Sub
  15. '========== ⇩(76) 予約プロシージャ(フォーム → シート:Private+引数有り) ============
  16. Private Sub CommandButton46_Click()
  17. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S04 " & L & "," & """" & S & """" & "'"
  18.  Application.OnTime Now() + TimeValue("0:00:01"), "'Sheet1.Exec_S04 " & L & "," & """" & S & """" & "'"
  19. End Sub
  20. '========== ⇩(77) 予約プロシージャ(フォーム → ブック:Public+引数有り) ============
  21. Private Sub CommandButton47_Click()
  22. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S05 " & L & "," & """" & S & """" & "'"
  23.  Application.OnTime Now() + TimeValue("0:00:01"), "'ThisWorkbook.Exec_S05 " & L & "," & """" & S & """" & "'"
  24. End Sub
  25. '========== ⇩(78) 予約プロシージャ(フォーム → ブック:Private+引数有り) ============
  26. Private Sub CommandButton48_Click()
  27. ' Application.OnTime Now() + TimeValue("0:00:01"), "'Exec_S06 " & L & "," & """" & S & """" & "'"
  28.  Application.OnTime Now() + TimeValue("0:00:01"), "'ThisWorkbook.Exec_S06 " & L & "," & """" & S & """" & "'"
  29. End Sub
図36


今回は「フォームモジュール上の実行プロシージャは、どこからも呼び出せそうにない」ので使わなかったのですが、とりあえず実行プロシージャは図37のものを使って試してはみました。
  1. '========== ⇩(79) フォームモジュールの実行プロシージャ(Public) ============
  2. Public Sub Exec_S07(Optional L As Long = 456, Optional S As String = "DEF")
  3.  MsgBox "userform1/Public" & vbNewLine & L & vbNewLine & S
  4. End Sub
  5. '========== ⇩(80) フォームモジュールの実行プロシージャ(Private) ============
  6. Private Sub Exec_S08(Optional L As Long = 456, Optional S As String = "DEF")
  7.  MsgBox "userform1/Private" & vbNewLine & L & vbNewLine & S
  8. End Sub
図37


6.まとめ

OnTimeメソッドで呼び出す(≒予約をする)実行プロシージャは、一般的には「標準モジュールのみ」「Publicのみ」という説明がされていますが、「Privateでも、またシートモジュールやブックモジュール上に置かれていても実行可能」な事が今回検証できました。
シートモジュールやブックモジュール上の実行プロシージャは、モジュール名を付けないと呼び出せません。しかし標準モジュール上の実行プロシージャは、「Private」且つ「呼出し側で引数を付ける」時のみ「標準モジュールオブジェクトの指定が必要」という、ちょっと複雑なルールです。

標準モジュールのオブジェクト名(例:Module1)を実行プロシージャ名に「常に付けておく」という選択肢もあるとは思いますが、本来Privateは「自モジュール内からのみアクセス可能」という事ですから、基本は「OnTimeでは、実行プロシージャを標準モジュールに置き、且つPublicプロシージャのみを呼び出す」事を最優先にするべき と思います。
但しMicrosoftも禁止(≒シートやブックの実行プロシージャは呼び出せない)している訳では無いので、必要な場合は使っても良いのかもしれません。その際、理由をコメントしておく事は必須と思います。

アプリ実例・関連する項目

再計算されたか否かのチェックをイベントで取得
OLEObjectのラベルカレンダー(同一ブック内)
セル色変更の情報をイベント風に受け取る

サンプルファイル

OnTimeメソッドの第一・第二パラメータ設定方法(its-037.xlsm)
セキュリティ向上を目的として「インターネット経由でダウンロードしたOfficeファイル(Excel等)のマクロは、既定でブロック」されるようにOfficeアプリケーションの既定動作が変更になりました。(2022年4月より切替開始)
解除の方法については「ダウンロードファイルのブロック解除方法」を参照下さい。