コマンドボタンに表示される文字列は、CommandButtonのCaptionプロパティで操作できます。次のコードは、ボタンをクリックするたびに、そのボタンの文字列を変更します。なお、ボタンの文字列は、デザイン段階で「実行」に設定しておいてください。
Private Sub CommandButton1_Click() With CommandButton1 If .Caption = "実行" Then .Caption = "中止" Else .Caption = "実行" End If End With End Sub
こうした、ボタンの文字列変更は、ひとつのボタンを「実行」と「中止」に使い分けるときなどに便利です。たとえば、すごく時間のかかる処理があったとします。それを「実行」ボタンで開始するのですが、途中で処理を中止するようなとき、最初の「実行」ボタンが処理中は「中止」ボタンになっていれば、同じボタンを操作するだけで済みます。Windowsの一般的なUIでは、そういうのが多いですよね。以下に、そのやり方を解説します。
こんな感じにデザインします。たとえば、コマンドボタンで、次のような処理をします。
Private Sub CommandButton1_Click() Dim i As Long For i = 1 To Rows.Count Cells(i, 1) = i ''恐ろしく時間のかかる処理...orz Next i End Sub
もし、上の処理が一瞬で終わってしまうような高速なパソコンをお使いの方は、何か時間のかかる処理を考えてください。さて、まず処理を開始したときに、ボタンの文字列を変えます。
Private Sub CommandButton1_Click() Dim i As Long CommandButton1.Caption = "中止" For i = 1 To Rows.Count Cells(i, 1) = i Next i CommandButton1.Caption = "実行" End Sub
しかし、これだけでは、ボタンの文字列が変わりません。最初の「.Caption = "中止"」を実行したあと、すぐに膨大な処理に突入してしまいましたので、ボタンの文字列変更が反映されないのです。こんなときは、DoEventsを実行して、制御をCPUに戻してやります。
Private Sub CommandButton1_Click() Dim i As Long CommandButton1.Caption = "中止" DoEvents For i = 1 To Rows.Count Cells(i, 1) = i Next i CommandButton1.Caption = "実行" End Sub
UserFormを再描画するという意味では、Me.Repaintでもいいですね。
さて、ボタンの文字列が、処理前は「実行」で、処理中は「中止」なのですから
というようにします。途中で処理を中止するというのは、次のように考えます。
まず、ボタンがクリックされたら、ボタンの文字列(Captionプロパティ)を調べます。ボタンが[実行]だったら、そのまま長い時間のかかる処理に突入します。
長い時間のかかる処理では、本来の処理の途中でユーザーが[中止]ボタンをクリックしたかどうかを常にチェックします。もし、ユーザーが中止を選択したのなら、処理を中止します。
一方、ボタンがクリックされたとき、その文字列が[中止]だったら、[中止]ボタンがクリックされたことを長い処理に伝えます。そのために、ひとつ変数を用意します。ここではStopFlagとしました。
ボタンの文字列が[中止]だったら、[中止]ボタンがクリックされたのですから、そこで変数StopFlagにTrueをセットします。
長い処理は、本来の処理の途中で変数StopFlagがTrueかどうかを判定します。もしTrueだったら[中止]ボタンがクリックされたと判断して、処理を中止します。変数StopFlagがFalseだったら、[中止]ボタンはクリックされていないのですから、処理を続行します。
Dim StopFlag As Boolean Private Sub CommandButton1_Click() Dim i As Long Select Case CommandButton1.Caption Case "実行" CommandButton1.Caption = "中止" Label1.Caption = "[中止]ボタンで中止します" DoEvents For i = 1 To Rows.Count Cells(i, 1) = i DoEvents If StopFlag = True Then Exit For Next i CommandButton1.Caption = "実行" Label1.Caption = "" StopFlag = False Case "中止" If MsgBox("中止しますか?", vbYesNo) = vbYes Then StopFlag = True End Select End Sub
ここでのポイントはFor Next内のDoEventsです。DoEventsステートメントは、制御をWindowsに解放するステートメントです。非常に時間のかかる長いFor Nextなどでは、そのループが終わるまで、VBAがCPUを乗っ取ってしまい、他の処理ができなくなることがあります。そうなると、ユーザーが[中止]ボタンをクリックしたというイベントさえ、For Nextの中に割り込めなくなります。そうならないために、時間のかかるFor Next中でDoEventsを実行して、瞬間的に制御をWindowsへ解放してやります。パソコンの環境にもよりますが、今回のような割り込み処理では、こうしたDoEventsは必須です。