フォームを高速で連打したときイベントが発生しない

解決


ccd  2007-04-05 12:07:36  No: 98487

フォームを高速で連打したときイベントが発生しない(XP,VB6)

コマンドボタンを高速で連打したときとは、ちゃんとコマンドボタンのクリックイベントが発生するのに、フォームを高速で連打したときは、フォームのクリックイベントが発生しないことがあります(と言うか、反応が間に合わないようです)。
下のコードで試したら分かると思いますが、前者と後者では連打したときのリストボックスに項目が追加されていくスピードが違うと思います。同じ簡単な処理なのに、何故なのでしょうか?
どうにもならないことなのでしょうか。

フォームをいくら高速でクリックしても、ちゃんとクリックイベントが発生するようにするにはどうすればいいでしょうか?  何かいい方法がないものでしょうか。
どうか、ご教授のほどよろしくお願い致します。

Private Sub Command1_Click()
    List1.AddItem "aaa"            
End Sub

Private Sub Form_Click()
    List1.AddItem "aaa"            
End Sub


魔界の仮面弁士  2007-04-05 17:57:18  No: 98488

> 何故なのでしょうか?
フォームには DblClick イベントがありますが、
ボタンにはそのイベントが無いから、とか。


ccd  2007-04-05 23:55:55  No: 98489

ご回答ありがとうございます。

> フォームには DblClick イベントがありますが、
> ボタンにはそのイベントが無いから、とか。

下のようにMouseDownイベントに置いても、クリックイベントに置いたときと同じ結果に・・・
Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    List1.AddItem "aaa"
End Sub

実は、フォームに自分でボタンの絵を描画して独自コマンドボタンみたいなものを作ろうとしていたのですが、フォームのMouseDownイベントにボタンが凹む絵を描く処理を置き、MouseUpイベントにボタンが上がる絵を描く処理を置いて実現しようとしたのですが、ゆっくり押したときはうまくいくのですが連打したときにうまく凹んでくれないことがあったり、凹んだままになってしまったりで、困っていました。

速いクリックにも対応する独自ボタンを作るにはどうすればいいでしょうか?
サブクラス化してMouseDownイベント(WM_LBUTTONDOWNメッセージ)をフックしてみたのですがそれでも結果は同じでした。

よろしくお願い致します。

実際のプログラムを簡略化したものです。
Private Declare Function DrawEdge Lib "user32" (ByVal hDC As Long, qrc As RECT, ByVal edge As Long, ByVal grfFlags As Long) As Long

Private Type RECT
  Left As Long
  Top As Long
  Right As Long
  Bottom As Long
End Type

Dim R As RECT

Private Sub Form_Load()
    Form1.AutoRedraw = True
End Sub

Private Sub Form_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
    R.Left = 50
    R.Top = 50
    R.Right = 100
    R.Bottom = 80
    DrawEdge hDC, R, 10, 15
    Form1.Refresh
End Sub

Private Sub Form_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    R.Left = 50
    R.Top = 50
    R.Right = 100
    R.Bottom = 80
    DrawEdge hDC, R, 5, 15
    Form1.Refresh
End Sub


  2007-04-06 07:42:29  No: 98490

>サブクラス化してMouseDownイベント(WM_LBUTTONDOWNメッセージ)をフックしてみた

おつかれさま・・・

それよか、もっと基本に立ち返って
FormをClickした時、DoubleClickした時に、
何のイベントが、どゆ順番で発生するかを
確認することをオススメします・・・。

そこを理解しないと解決しないのではないでしょうか?
魔界の仮面弁士さまもそれを言いたいのだと思いますが・・・。


ccd  2007-04-06 08:50:34  No: 98491

解決法をご存知なのですか?
是非教えてください!!

> それよか、もっと基本に立ち返って
> FormをClickした時、DoubleClickした時に、
> 何のイベントが、どゆ順番で発生するかを
> 確認することをオススメします・・・。

MouseDown > MouseUp > Click > DblClick
の順番で発生することがわかりましたが、それが何か意味があるのでしょうか?


魔界の仮面弁士  2007-04-06 10:45:26  No: 98492

えぇと、イベントの順番がどうこうという話ではなく、
「ダブルクリック イベントを認識するウィンドウだから問題がある」ので、
「ダブルクリックを認識しないウィンドウなら良いのかな」と
漠然と思っただけで……私自身は回答を持っているわけではないです。(汗

これが VB.NET なら、
  MyBase.SetStyle(ControlStyles.StandardDoubleClick, False)
だけで解決できそうなのですが、VB6 の場合はどうしたものやら。


K・今川  2007-04-06 16:15:50  No: 98493

ダブルクリックイベントを必要としないのであれば
ダブルクリックイベントからクリックイベントを呼び出せは良いのでは?

Private Sub Form_DblClick()
    Call Form_Click
    Call Form_Click
End Sub


GOD  2007-04-06 19:17:44  No: 98494

>Private Sub Form_DblClick()
>    Call Form_Click
>    Call Form_Click
>End Sub
>
はダメですよ。
Clickの後にDblClickが発生しているのでここでクリックの処理を2回分やってしまうと計3回分の処理をしてしまいます。(実質のクリックは2回)

> MouseDown > MouseUp > Click > DblClick
> の順番で発生することがわかりましたが、それが何か意味があるのでしょうか?
>
私の環境(使用環境Win2000SP4,XPSP2)では MouseDown > MouseUp > Click > DblClick > MouseUp となっていました。私はイベント順を見ることにより DblClick のところではMouseDown イベントが発生していないということを認識できたので意味は十分ありましたが。(DblClick でMouseDown と同等のコードを記載することによりそこそこの連打にも対応できているように見えましたよ。)
それとも環境の違いにより、発生するイベントが変わってくるんでしょうかね。
上記のイベント順を見ると最後に必ず MouseUp が来ているので凹みっぱなしになることはないと思うのですが。軽く実験したけどそのような現象は発生しなかったですね。万回とかテストするとイベントが潰れて発生するのかな?
ただ、イベントが潰れて通知されてこないと対処のしようが無いと思うので諦めるしかないかと。


K・今川  2007-04-06 21:17:23  No: 98495

>>Private Sub Form_DblClick()
>>    Call Form_Click
>>    Call Form_Click
>>End Sub
>>
>はダメですよ。
>Clickの後にDblClickが発生しているのでここでクリックの処理を2回分やってしまうと計3回分の処理をしてしまいます。(実質のクリックは2回)

すみません。
私はイベント順までは見ておらずccdさんの最初の質問にあったコードで
試しただけなのですが改めてコードを動かしてみたら確かに一回余分にaaa
が追加されていました。
私の環境は  winXP SP2、VB6です。

ただ、先にクリックイベントが発生するなら、クリックイベントとダブルクリックイベント
双方にコードがあるとダブルクリックイベントだけを実行することが出来ないんですね。


K.J.K.  2007-04-06 21:39:50  No: 98496

Windows API方面からのアプローチとしては、やりやすいかどうかは
ともかくとして、VB6の場合は、

1,ボタンの元にはCommandButtonを用いる。(OptionBox、CheckBoxでも可)
2,上記のコントロールのStyleプロパティを1(vbButtonGraphical)にしておく。
3,コントロールをサブクラス化してWM_MOUSEHOVERに反応できるようにする。
  TrackMouseEventも使うことになります。
4,そのコントロールを貼り付けたForm/PictureBox/Frame/UserControlも
  サブクラス化し、WM_DRAWITEMに反応できるようにする。WM_DRAWITEM
  を受け取ったら、そのボタンを状況に応じて適切に描画する。

というようになると思います。

Styleプロパティを1(tbrFlat)にしたToolBarコントロールで代用する方が、
楽ではないか、とも思います。


ccd  2007-04-07 05:46:34  No: 98497

皆様、ありがとうございました。

APIのGetKeyStateでマウスの状態を調べる方法で、なんとか実現できました!! K.J.K.さんのご提示いただいた方法も、スキルがアップしてきたら挑戦したいと思います。途中、不心得な書き込みもありましたが、これで週末はいい花見ができそうです。
どうもありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加