Acccess2003で久しぶりにバッチ処理を書いていたら、DoEventsにハマりました。○| ̄|_
一つのフォームの中に、作業1ボタンと作業2ボタンを準備し、作業1ボタンをクリックし、作業1のプロシージャーが走っている間に作業2ボタンをクリックすると、作業2がどうやら走っている…。
ええーー、そうだったっけ?
と思って調べてみると、作業1のプロシージャー内のDoEventsが原因らしい。ヘルプを見ると、
DoEvents 関数を使ってオペレーティング システムに制御を渡しています。
DoEventsでOSに一旦制御を返しているせいで、ボタンクリックのイベントを拾ってこれるようになるわけですね。そりゃそうか。こいつを利用してキャンセルボタンを実行させることもできる、と。
作業1が終了するまでロックをかけたいわけですが、その方法はあとまわしにするとして、ちょっと面白い動きをしていたので実験してみました。
まず、作業1ボタンと作業2ボタンを準備し、次のようなサンプルソースを準備。
Private Sub cmd作業1_Click() Dim i As Long For i = 0 To 10000 Me.lbl_Count1.Caption = Format(i, "#,##0") DoEvents Next End Sub
Private Sub cmd作業2_Click() Dim i As Long For i = 0 To 10000 Me.lbl_Count2.Caption = Format(i, "#,##0") DoEvents Next End Sub
そして
- 作業1ボタンをクリック
- 作業1が走っている間に作業2ボタンをクリック
してみると、次のような順序で作業を終了しました。
- 作業1をクリック→作業1が走り出す。
- 作業1の途中で作業2をクリック→作業1を中断して、作業2が走り出す。
- 作業2が完了した後、作業1が再開される。
うーん、作業1の途中で作業2がはじまるのは、OSへ制御が戻っている部分が如実で面白いなぁ。そして作業2が終わると作業1を再開する…(これはちょっと予想外)。
ちなみにDoEventsを書いていなければ、自動的にそのイベントのプロシージャーを抜けるまでAccessはロックがかかっています。しかし、ロジックの中でDoEventsを書きたいし、作業の間は各種ボタンイベント等にはロックをかけたい、というときどうすれば良いか?
Accessの場合、フォーカスをもっているコントロールには、ロックをかけられません。つまり作業1ボタンをクリックした場合、作業1ボタンにフォーカスがありますから、作業2ボタンなど他のコントロールにはロックをかけられても、作業1ボタン自身にはロックをかけられないのですね。よって、小技テクニック「透明ボタンを作る」(…なんでボタンにこんなプロパティがあるんだろー…。やっぱりこの為?)。
- 新しくダミーのボタンをフォーム上作成する。
- ダミーボタンの[プロパティ]→[書式]→[透明]で[はい]に設定する。
- で、このダミーボタンにフォーカスをとりあえず、移動させてしまう。
作業1ボタンのイベントプロシージャーの場合だと、こんな感じ。
Private Sub cmd作業1_Click() Me.cmdダミー.SetFocus Me.cmd作業1.Enabled = False Me.cmd作業2.Enabled = False Dim i As Long For i = 0 To 10000 Me.lbl_Count1.Caption = Format(i, "#,##0") DoEvents Next Me.cmd作業1.Enabled = True Me.cmd作業2.Enabled = True End Sub
こんなんで回避できちゃうんですねぇ。まぁグローバル変数とかを使って判定するのもテだとは思いますが。ロックをかけたほうが、ユーザーも見た目でわかりますものね。
0 件のコメント:
コメントを投稿