Extra Mausevents ohne TrackMouseEvent

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Extra Mausevents ohne TrackMouseEvent

Beitrag von edel »

Mit TrackMouseEvent kann man feststellen wann der Cursor ein Fenster
betritt oder wieder verlaesst. Gibt es nur nicht fuer alle Windows Versionen.
Folgende 2 Beispiele zeigen wie es auch ohne TrackMouseEvent geht.

Fuer Fenster :

Code: Alles auswählen

Procedure CaptureMouseEventsOnWindowCB(hWnd,uMsg,wParam,lParam)
	Protected rc.rect,pt.point,pt2.point
	Protected OldProc.l = GetWindowLong_(hWnd,#GWL_USERDATA)
		
	If #WM_MOUSEMOVE = uMsg
			
		GetClientRect_(hWnd,rc)					
		
		pt\x  = (lparam & $0000FFFF)
		pt\y  = (lparam >> 16)
		
		pt2\x = pt\x
		pt2\y = pt\y
						
		ClientToScreen_(hWnd,pt2)
		
		If PtInRect_(rc,pt\x,pt\y) And WindowFromPoint_(pt2\x,pt2\y) = hWnd
			If Not GetCapture_() = hWnd
				SetCapture_(hWnd)													
				Debug "ENTER : WIN = " + Str(GetProp_(Hwnd,"PB_WindowID")-1)
			EndIf					
		Else									
			Debug "LEAVE : WIN = " + Str(GetProp_(Hwnd,"PB_WindowID")-1)
				ReleaseCapture_()				
			EndIf 
		
	EndIf 

	ProcedureReturn CallWindowProc_(OldProc,hWnd,uMsg,wParam,lParam)
EndProcedure

Procedure CaptureMouseEventsOnWindow(hWindow)
	Protected oldProc = SetWindowLong_(hWindow,#GWL_WNDPROC,@CaptureMouseEventsOnWindowCB())		
	SetWindowLong_(hWindow,#GWL_USERDATA,oldProc)
EndProcedure


; TEST
Procedure Main()	
	Protected Event.l

	OpenWindow(0,#PB_Ignore,#PB_Ignore,300,300,"Test")
	OpenWindow(1,#PB_Ignore,#PB_Ignore,100,100,"Test")
	
	CaptureMouseEventsOnWindow(WindowID(0))
	CaptureMouseEventsOnWindow(WindowID(1))
	
	Repeat 
		event = WaitWindowEvent()

	Until event = #PB_Event_CloseWindow	
	

EndProcedure:Main()

Fuer Gadgets

Code: Alles auswählen

Procedure CaptureMouseEventsOnGadgetCB(hWnd,uMsg,wParam,lParam)
	Protected rc.rect
	Protected OldProc.l = GetWindowLong_(hWnd,#GWL_USERDATA)
		
	If #WM_MOUSEMOVE = uMsg
			
		GetClientRect_(hWnd,rc)					
		
		If PtInRect_(rc,(lparam & $0000FFFF),(lparam >> 16))
			If Not GetCapture_() = hWnd
				SetCapture_(hWnd)													
				Debug "ENTER : GADGET = " + Str(GetProp_(Hwnd,"PB_ID"))
			EndIf					
		Else									
			Debug "LEAVE : GADGET = " + Str(GetProp_(Hwnd,"PB_ID"))
				ReleaseCapture_()				
		EndIf 
		
	EndIf 

	ProcedureReturn CallWindowProc_(OldProc,hWnd,uMsg,wParam,lParam)
EndProcedure

Procedure CaptureMouseEventsOnGadget(hGadget)
	Protected oldProc = SetWindowLong_(hGadget,#GWL_WNDPROC,@CaptureMouseEventsOnGadgetCB())		
	SetWindowLong_(hGadget,#GWL_USERDATA,oldProc)
EndProcedure



;TEST
Procedure Main()	
	Protected Event.l
	Protected hWnd.l
	
	hWnd = OpenWindow(0,#PB_Ignore,#PB_Ignore,300,300,"Test")
	
	CreateGadgetList(hWnd)
	hBut0 = ButtonGadget(0,10,10,20,20,"0")
	hBut1 = ButtonGadget(1,40,10,20,20,"1")
	
	CaptureMouseEventsOnGadget(hBut0)
	CaptureMouseEventsOnGadget(hBut1)
		
	Repeat 
		event = WaitWindowEvent()

	Until event = #PB_Event_CloseWindow	
	

EndProcedure:Main()
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Vielen Dank für das Bereitstellen dieses Codes. :allright:

Jedoch funktioniert er nicht wie gewünscht, da du WindowFromPoint_() verwendest.
Füge einfach folgenden Code in Main() ein:

Code: Alles auswählen

    CreateGadgetList(WindowID(0))
    ButtonGadget(#PB_Any, 0, 0, 300, 300, "FETTER BUTTON")
Egal ob Button, TextGadget oder sonst etwas, die Maus muss wirklich nur auf dem Fenster und nicht auf einem Gadget sein, damit alles korrekt erkannt wird.

Woran liegt das?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
RSBasic
Admin
Beiträge: 8047
Registriert: 05.10.2006 18:55
Wohnort: Gernsbach
Kontaktdaten:

Beitrag von RSBasic »

Wieso ermittelt man nicht ganz einfach mit DesktopMouseX() und DesktopMouseY()?
Aus privaten Gründen habe ich leider nicht mehr so viel Zeit wie früher. Bitte habt Verständnis dafür.
Bild
Bild
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Es ist egal, wie man an die Koordinaten kommt, du verstehst das eigentliche Problem nicht: WindowFromPoint_()

Lies mein erstes Posting noch mal.
Und sieh dir den Thread "Ist die Maus irgendwo in meinem Fenster?" durch.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

AND51 hat geschrieben:Jedoch funktioniert er nicht wie gewünscht, da du WindowFromPoint_() verwendest.

Füge einfach folgenden Code in Main() ein:

Code: Alles auswählen

    CreateGadgetList(WindowID(0))
    ButtonGadget(#PB_Any, 0, 0, 300, 300, "FETTER BUTTON")
Egal ob Button, TextGadget oder sonst etwas, die Maus muss wirklich nur auf dem Fenster und nicht auf einem Gadget sein, damit alles korrekt erkannt wird.

Woran liegt das?
1. Natuerlich funktioniert das wie gewuenscht. Zumindest so
wie ich es haben wollte. Eine 'kleine' Alternative zu TrackMouseEvent eben.
2. Ein Textgadget ist ein Static-Control und sendet (ohne ss_notify) alle
Nachrichten an das Parent-Fenster. Wuerde also funktionieren.
3. Jedes andere Fenster behandelt solche Nachrichten selber. Du hast
also dein Fenster verlassen wenn du mit der Maus ueber ein Child gehst.

Der einzige Weg der mir dazu einfaellt ist alle Child-Fenster zu subclassen
und die Nachricht WM_MOUSEMOVE abzufangen, die Koordinaten
umzuwandeln und dann an das Hauptfenster umzuleiten.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

> Du hast also dein Fenster verlassen wenn du mit der Maus ueber ein Child gehst
Achso... Dann habe ich das grundsätzlich missverstanden. Denn ich bin der Meinung, da das Child (z. B. ein Button) geographisch gesehen im Fenster liegt, zählt es zum Fenster.

> The WindowFromPoint function retrieves a handle to the window that contains the specified point
heißt für mich, dass wenn ich auf einem Button bin, der im Fenster liegt, dann ist die Koordinate dem Fenster zuzuordnen, nicht dem Button.

Trotzdem danke, dass du mir das mal richtig gesagt hast, dass ein Fenster als verlassen gilt, wenn die Maus über ein Child geht, wusste ich so nicht.

> Der einzige Weg der mir dazu einfaellt ist alle Child-Fenster zu subclassen
Sorry, aber... Nochmal auf deutsch? Davon hab ich keine Ahnung. :|
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
Tafkadasom2k5
Beiträge: 1578
Registriert: 13.08.2005 14:31
Kontaktdaten:

Beitrag von Tafkadasom2k5 »

Subclassing bedeutet nichts anderes als Nachrichten umzuleiten/abzufangen.

Wie du bestimmt weißt, sind Controls(Gadgets) nichts Anderes als eigene Fenster, die eine standard-callback haben, die von Windows bereitgestellt wird. Beim Button wäre das eben die Knopf-gedrückt-Animation, und das Senden der Information über den Knopfdruck an das Parentwindow.

Das Problem ist, dass Childwindows- in dem Fall der Knopf, die Anderen Nachrichten (#WM_PAINT/#WM_MOUSEMOVE) ja nicht an das Parentwindow schicken- eigentlich geht das Parentwindow ja auch nichts davon an ;)
In diesem Fall willst du aber die Nachrichten #WM_MOUSEMOVE zB haben, um zu schauen, ob die Mause innerhalb des Childwindows liegt. Also musst du diverse Informationen umleiten: Subclassen.

Beim Subclassen machst du dann Folgendes:
Du erfragst beim microkernel deines Vertrauens ( :lol: , dass wir hier nicht monolithic arbeiten find ich btw auch ganz gut :mrgreen: ) das Fensterhandle, des Childwindows. Über

Code: Alles auswählen

hChildWindow.l = WindowID(CHILDWINDOWNUMMER)
hOldCallback.l= SetWindowLong_(hChildWindow, #GWL_WNDPROC, @Subclasscallback)
SetWindowWord_(hChildWindow, 1, hOldCallback)
Leitest du ALLES auf eine andere Callback um. @SUBCLASSCALLBACK Ist die Adresse deines Callbacks, der das Parentfenster steuert.

Das Problem ist jetzt, dass die Callback deines Childwindows jetzt nicht mehr genutzt wird: Alles, was dein Childwindow jetzt empfängt, wird an die Callback deines Parentfensters geleitet. Jetzt ist es so, als hätte die Maus das Parentfenster nie verlassen, wenn sie über das Childfenster hovert. Da du aber bestimmt möchtest, dass die anderen Befehle, die in der alten Callback noch standen auch abgearbeitet werden, musst du diese manuell ansteuern.

Die Adresse, die zum alten Callback führte, steht in diesem Fall in "hOldCallback", der Rückgabewert des oben genannten Befehls. In der Callback deines Parentwindows weist du aber nicht, wie diese Adresse war, diese liegt jetzt ja dooferweise innerhalb der alten Callback, in der Variable. Deshalb das SetWindowWord_(). SetWindowWord hat 8 Speicherzellen pro Fenster frei, um dort Sachen zwischenzuspeichern. Ist sozusagen ein Trick. Andere Möglichkeiten wären globale Arrays oder wasauchimmer. Aber für sowas find ich das gut ;)

Jetzt gehst du ganz ans Ende deiner MainwindowCallback, und überprüfst dort, welches Fenster die letzte Nachricht empfangen hat.

Code: Alles auswählen

If hWnd = WindowID(CHILDWINDOW)
  hOldCallback = GetWindowWord_(WindowID(CHILDWINDOW),1)
  ProcedureReturn  CallWindowProc_(hOldCallback , hWnd, wMsg, wParam, lParam)
EndIf
Du sagst Windows also, er soll folgende Callback abarbeiten, mit folgenden Werten- die Werte, die du am Anfang der Callback bekommen hast. Weil das sind ja schließlich auch die Werte, die sonst die Callback deines Childs bekommen hätten.

So, viel trockene Theorie, aber sowas habe ich in Pure auch nch nicht gemacht. Aber ist von der Umsetzung her ungefähr so, wie ich das beschrieben habe.

Gr33tz
Tafkadasom2k5
OpenNetworkConnection() hat geschrieben:Versucht eine Verbindung mit dem angegebenen Server aufzubauen. 'ServerName$' kann eine IP-Adresse oder ein voller Name sein (z.B.: "127.0.0.1" oder "ftp.home.net").
php-freak hat geschrieben:Ich hab die IP von google auch ned rausgefunden!
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Danke für die ausführliche Antwort!
Um das zu verstehen muss ich es später nochmal durchlesen, das klappt nicht auf Anhieb... Werd ich etwa schon alt? :?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Benutzeravatar
edel
Beiträge: 3667
Registriert: 28.07.2005 12:39
Computerausstattung: GameBoy
Kontaktdaten:

Beitrag von edel »

Unter 32bit benutzt man kein GetWindowWord mehr sondern GetWindowLong.
Benutzeravatar
Tafkadasom2k5
Beiträge: 1578
Registriert: 13.08.2005 14:31
Kontaktdaten:

Beitrag von Tafkadasom2k5 »

Mh, ich wollte eigentlich ne Variabe zwischenspeichern. Kann auch sein, dass ich den Befehl in der Eile verdreht habe. AFAIK hat jedes Fenster 8 eigene Speicher...

Kennst du diesen Befehl? Mir fällt der API-Equivalent nämlich nicht mehr ein. Kenn gerade nur den PowerBASIC-BEfehl, der sollte aberlediglich ne Art Wrapper für ne API sein. Es geht eben darum die alte Callback Adresse im Fenster irgendwie direkt zu speichern.

Gr33tz
Tafkadasom2k5
OpenNetworkConnection() hat geschrieben:Versucht eine Verbindung mit dem angegebenen Server aufzubauen. 'ServerName$' kann eine IP-Adresse oder ein voller Name sein (z.B.: "127.0.0.1" oder "ftp.home.net").
php-freak hat geschrieben:Ich hab die IP von google auch ned rausgefunden!
Antworten