DOBON.NET DOBON.NETプログラミング掲示板過去ログ

フォームの裏に隠れたものをクリック

環境/言語:[VB.NET2003]
分類:[.NET]

はじめまして。たけぼんといいます。

今パソコン名を取得して描画するというプログラムをVB.NETで作っています。
Bitmapにパソコン名を描画してそれをフォームに貼り付け。その後不要な部分を
透明化して、文字だけが表示されるといったプログラムです。
フォームの位置は固定なのですが、アイコンの真上に来る可能性がある位置という
仕様なんです。あとこのフォーム(文字)はTopMost = Trueで最前面に表示されて
います。
フォントはわりと大きなサイズのものを使っているので不要な部分は透明に
したとしても見えない部分がわりとあります。

たとえばアイコンの真上にこのプログラムが来た場合、透明になっている部分を
クリック(アイコンを)したらアイコンは反応するのですがちょうど文字に隠れた
部分をクリックしたくてもできません。
(どうやらフォームがクリックされていると認識されるようでアイコンは無反応)

なので、マウスをフックしてクリックされたときにフォームのVisibleをFalseに
して非表示。その後CallNextHookExしてからまたフォームのVisibleをTrueに
という風なことをしてみましたが、フォームはたしかにVisibleを操作してるので
一瞬点滅したかのように見えますが、マウス制御ができていないようでうまく
いきません。

何かよいアイデアはないでしょうか?。
すいませんがよろしくお願いします。
■No7331に返信(たけぼんさんの記事)
> はじめまして。たけぼんといいます。
>
たけぼんさん はじめまして
平ちゃんです。
なかなか面白そうですね。
フォームのVisibleをFalse にすると制御できなくなるような
気がします。
回答にならないかもしれませんが、クリックでフォームが反応すると
フォームの位置がずれるようにする案はどうでしょうか?
> たとえばアイコンの真上にこのプログラムが来た場合、透明になっている部分を
> クリック(アイコンを)したらアイコンは反応するのですがちょうど文字に隠れた

非常に安直ですが、自ウィンドウ直下のウィンドウハンドルを取得して、
PostMessageでWM_LBUTTONDOWNなどを送信するのが一番かと・・・。

#デスクトップのハンドルはGetDesktopWindowではなく、
#ListViewのハンドルを取得しなければなりません。
お返事ありがとうございます、たけぼんです。平ちゃんさん、antさんありがとう
ございます。

>平ちゃんさん

仕様上座標を変更することができないので、クリック時にずらすといったことは
できません。
仮にクリックイベントでフォームをずらしても、フォームの下のものへのクリック
イベントはすでに「1回目のクリック」で処理されてしまってるので・・・。
フォーム自体に何か制御させたいのではなく、フォーム下にあるものを制御したい
ので、たぶんフォームそのものを非表示にしてフォーム下のものを制御するのは
問題ないかと思っています(すべて推測ですが)。

>antさん

> 非常に安直ですが、自ウィンドウ直下のウィンドウハンドルを取得して、
> PostMessageでWM_LBUTTONDOWNなどを送信するのが一番かと・・・。

この手も考えました。
実際「マウスカーソルのある位置にあるウインドウハンドルの取得」方法がわからず
どうしたものかと悩んでいます。
もしマウスカーソル下のウインドウハンドルを取得できたなら、マウスフックで
クリック時にフォームをVisibleにしてから座標位置のハンドルを取得して
PostMessageでメッセージを送信してあげればできる気がするのですが・・・。

引き続き調査しています。何かよいアイデアがありましたら宜しくお願いします。
たけぼんさん、こんにちは
mouose_eventもしくはSendInput APIを使用してはいかがでしょうか?

moouse_eventの例を貼っておきます。
ただし、FormのVisibleをfalse、trueとするとtrue時に
Formがアクティブになってしまうため、とりあえず位置
をずらしてmouse_event終了後に元に戻すようにしてあり
ます。

また、Sleepで少々待ちを作らないとうまくいかなったので
Sleepしてます。(値は適当)


−−−−−−−−−−−−−−−−−−−−−−−
Private Const MOUSEEVENTF_LEFTDOWN = &H2
Private Const MOUSEEVENTF_LEFTUP = &H4
Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Integer, ByVal dx As Integer, ByVal dy As Integer, ByVal cButtons As Integer, ByVal dwExtraInfo As Integer)

Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseDown
Dim pnt As Point
pnt = Me.PointToScreen(New Point(e.X, e.Y))
Dim l = Me.Left
Me.Left = 10000 'とりあえずの値です
System.Windows.Forms.Application.DoEvents()
System.Threading.Thread.Sleep(1)

Cursor.Position = pnt
mouse_event(MOUSEEVENTF_LEFTDOWN, pnt.X, pnt.Y, 0, 0)
mouse_event(MOUSEEVENTF_LEFTUP, pnt.X, pnt.Y, 0, 0)
System.Threading.Thread.Sleep(1)
Me.Left = l
End Sub
訂正
System.Windows.Forms.Application.DoEvents()

これ不要でしたm(__)m
> 実際「マウスカーソルのある位置にあるウインドウハンドルの取得」方法がわからず
> もしマウスカーソル下のウインドウハンドルを取得できたなら、マウスフックで
> クリック時にフォームをVisibleにしてから座標位置のハンドルを取得して
> PostMessageでメッセージを送信してあげればできる気がするのですが・・・。

あれ?何か自分が思っていたものとちょっと違うみたいです。(^^;
しかし、マウスカーソルの位置にあるウィンドウハンドルを取得するのは
WindowFromPoint関数で一発ですので一応書いておきます。
どうもです。たけぼんです。

>ゆさん
最初に平ちゃんさんが言っていたアイデアとさらにマウスクリックイベントを発生
させる技とを混ぜて行うことにより見事成功しました。
sleepの設定数が1だと時々反応がおかしいようなので、今はとりあえず10にして
います。

これでなんとかなりそうです。
本当にありがとうございました。とても助かりました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板