Enabledがfalse中のクリックイベントがtrue後に実行されてしまいます。
投稿者 魔界の仮面弁士  (社会人)
投稿日時
2016/12/13 01:41:50
キーボード入力やマウス操作、画面描画などといった処理は
「ウィンドウ メッセージ」という、一種のイベント通知として扱われます。
そしてこれらのメッセージが処理されるのは、そのアプリケーションが
ほかの作業をしていないとき、いわゆる「アイドル時」に限られます。
何か処理を行っている最中に来たメッセージは、アイドル状態になるまで
待ち行列にキューイングされ、処理可能になった時点で一気に処理されます。
Enabled = False の状態であれば、クリック操作は破棄されるはずなのでですが、
アイドル時でなければメッセージは処理されません。Click イベントという
作業をしている最中ゆえ、その破棄処理さえも待ち状態になっているわけです。
Button1_Click を抜けてアイドル時になった瞬間には破棄可能に戻りますが、
その時点では、Enabled = True に戻されているわけですから、
結果的に、クリック処理がそのまま走ってしまう、ということです。
対処方法としては、Application の Idle イベントを使うと良いでしょう。
上記では、長い処理を実施する前に、isEventProcessing 変数を True にしています。
そして、isEventProcessing フラグが True の間は、Click イベントが来ても
なにも処理しないように If 文で無視させることで、イベントの再入を防ぐようにします。
処理が終わり、アプリケーションがアイドル状態になると
Application の Idle イベント が発生しますので、そこで
isEventProcessing を False に戻してやります。
なおサンプルでは、Button1_Click 内でマウスカーソルを変更していますが
これは必須ではありません。
もちろん、Button1_Click 内で Button1.Enabled を操作するのも自由です。
「ウィンドウ メッセージ」という、一種のイベント通知として扱われます。
そしてこれらのメッセージが処理されるのは、そのアプリケーションが
ほかの作業をしていないとき、いわゆる「アイドル時」に限られます。
何か処理を行っている最中に来たメッセージは、アイドル状態になるまで
待ち行列にキューイングされ、処理可能になった時点で一気に処理されます。
Enabled = False の状態であれば、クリック操作は破棄されるはずなのでですが、
アイドル時でなければメッセージは処理されません。Click イベントという
作業をしている最中ゆえ、その破棄処理さえも待ち状態になっているわけです。
Button1_Click を抜けてアイドル時になった瞬間には破棄可能に戻りますが、
その時点では、Enabled = True に戻されているわけですから、
結果的に、クリック処理がそのまま走ってしまう、ということです。
対処方法としては、Application の Idle イベントを使うと良いでしょう。
'対処案
Private isEventProcessing As Boolean = False
Private Sub Application_Idle(sender As Object, e As EventArgs)
isEventProcessing = False
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If Not isEventProcessing Then
isEventProcessing = True
Cursor = Cursors.WaitCursor
LongTimeAction()
Cursor = Cursors.Default
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
AddHandler Application.Idle, AddressOf Application_Idle
End Sub
Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
RemoveHandler Application.Idle, AddressOf Application_Idle
End Sub
上記では、長い処理を実施する前に、isEventProcessing 変数を True にしています。
そして、isEventProcessing フラグが True の間は、Click イベントが来ても
なにも処理しないように If 文で無視させることで、イベントの再入を防ぐようにします。
処理が終わり、アプリケーションがアイドル状態になると
Application の Idle イベント が発生しますので、そこで
isEventProcessing を False に戻してやります。
なおサンプルでは、Button1_Click 内でマウスカーソルを変更していますが
これは必須ではありません。
もちろん、Button1_Click 内で Button1.Enabled を操作するのも自由です。
対応したエクセルファイルを印刷するプログラムを作っています。
印刷処理に時間がかかるので、ボタンがクリックされるとプリンタにデータが
送られるまでの間、フォームのEnabledをfalseにして、ボタンが押されないよう
にしています。
しかし、false中にボタンがクリックされると、フォームがtrueに戻った後に、
ボタンのクリックイベントが発生してしまい、印刷がされてしまいます。
どうして、このようなことが起きてしまうのかわかりません。
false中にクリックされても、true後にイベントが発生しないようにするには
どうしたらよいのでしょうか?
ご存知の方がいらっしゃいましたら、お教えください。