Requesting help with using Gdip to display several images that each change on mouse over Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
scoobs525
Posts: 49
Joined: 19 Apr 2022, 16:39

Re: Requesting help with using Gdip to display several images that each change on mouse over

02 Aug 2023, 16:31

Hellbent wrote:
26 Jul 2023, 22:34
It looks like you are trying to create a custom radio control set.

Have a look at this.
This is written for windows 8+ and uses invisible text controls as a method of simplifying things.
Using this method you can directly call your buttons function / label and you can sort of ping the window to get a direct link to your control objects.

PRESS AND HOLD LALT to show the buttons.

Let me know if you have any questions.
Thank you, I tried to figure this out myself without asking for further help but I've hit another wall :(

This new code allows the 'active' functionality perfectly, but I can't figure out how to run a routine when a button is clicked. I tried adding in the MouseClickEvent function from the previous example (as well as things that refer to it, the button labels and label subroutines), but no luck - I'm also really struggling with replacing the buttons in the example with my image files. The DrawWindow function in this example also looks like it relies on the Text values in the buttons themsleves, which won't exist even if I do figure out how to use an image from a file here.


Once I've got the functionality side of things done, I'll be adding more buttons, so I then thought it might be easier to just bring the ToggleState function in to my existing script that already uses the image files. I got further with doing that, but button 2 in the end result is flickering and unpredictable - I'm an AHK beginner and going through the code with a fine cone is leaving me thinking I've figured it out, only to be more confused.



How can I replace the buttons in your newest example with png images files and how can I make clicking the button run a specific routine?
For example,
Click Button 1, Send 1
Click Button 2, Send 2

Thank you again
User avatar
Hellbent
Posts: 2114
Joined: 23 Sep 2017, 13:34

Re: Requesting help with using Gdip to display several images that each change on mouse over  Topic is solved

03 Aug 2023, 00:10

How can I replace the buttons in your newest example with png images files?
Here is the replacement code for the button graphics.

Replace these two functions ( and edit the paths to your images in the "AddControls" function ).

I wrote out the two buttons in different ways so that you can get a better sense of how things work. You can pick either approach, or a combo of both ( As is the case with the main window object [ Gui1 ] ).

Code: Select all

;###################################################################

AddControls( Gui1 ){
	
	Gui1.Controls := {}
	Gui1.Handles := []

	;**********************************************
	;**********************************************
	Gui1.Controls.Button_1 := { X: 10 , Y: 10 , W: 100 , H: 100 , Function: "ToggleState" , DefaultImage: Gdip_CreateBitmapFromFile( "Default.png" ) , HoveredImage: Gdip_CreateBitmapFromFile( "Hover.png" ) , PressedImage: Gdip_CreateBitmapFromFile( "Pressed.png" ) , DefaultImage_Sel: Gdip_CreateBitmapFromFile( "Default.png" ) , HoveredImage_Sel: Gdip_CreateBitmapFromFile( "Hover.png" ) , PressedImage_Sel: Gdip_CreateBitmapFromFile( "Pressed.png" ) }
	;**********************************************
	;**********************************************
	Gui1.Controls.Button_2 := {} ;create an associative array ( hearafter called an object unless specified )

	cc := Gui1.Controls.Button_2 ;cc is now the same object as the button object. acting on one is the same as acting on the other.

	cc.X := 120 ;adding a new property ( key: [ x ] ) and assigning a value to it
	cc.Y := 10
	cc.W := 100
	cc.H := 100

	cc.Function := "ToggleState"

	cc.DefaultImage := Gdip_CreateBitmapFromFile( "Default.png" )
	cc.HoveredImage := Gdip_CreateBitmapFromFile( "Hover.png" )
	cc.PressedImage := Gdip_CreateBitmapFromFile( "Pressed.png" )
	
	cc.DefaultImage_Sel := Gdip_CreateBitmapFromFile( "Default_Sel.png" )
	cc.HoveredImage_Sel := Gdip_CreateBitmapFromFile( "Hover_Sel.png" )
	cc.PressedImage_Sel := Gdip_CreateBitmapFromFile( "Pressed_Sel.png" )
	
	;**********************************************
	;**********************************************


	for k , v in Gui1.Controls	{
		cc := Gui1.Controls[ k ]
		Gui, % Gui1.Hwnd ":Add" , Text , % "x" cc.X " y" cc.Y " w" cc.W " h" cc.H " hwndhwnd"
		cc.Hwnd := hwnd
		cc.Name := k
		Gui1.Handles[ hwnd ] := cc 
		bd := Func( cc.Function ).Bind( Gui1 , hwnd )
		GuiControl, % Gui1.Hwnd ":+G", % hwnd , % bd
	}
	
}
;###################################################################
DrawWindow( Gui1 ){
	
	Gui1.ClearWindow()
	
	for k , v in Gui1.Controls	{ ;loop through all of the radio controls 
		
		cc := Gui1.Controls[ k ]  
		
		if( k = Gui1.SelectedControl ){
		
			if( k = Gui1.PressedControl ){
				; [ Selected and pressed ] 
				;Replace with your button ( same for below ).
				;Set "dispose" to zero so that you can use this image over and over.
				;Set "AutoUpdate" to zero so that everything can get drawn before the window updates with the new graphics.
				This.Gui1.DrawBitmap( cc.PressedImage_Sel , { X: cc.X , Y: cc.Y , W: cc.W , H: cc.H } , dispose := 0 , AutoUpdate := 0 )
			
			}else if( k = Gui1.HoveredControl ){
				; [ Selected and hovered ]
				This.Gui1.DrawBitmap( cc.HoveredImage_Sel , { X: cc.X , Y: cc.Y , W: cc.W , H: cc.H } , 0 , 0 )

			}else{
				; [ Selected and default ]
				This.Gui1.DrawBitmap( cc.DefaultImage_Sel , { X: cc.X , Y: cc.Y , W: cc.W , H: cc.H } , 0 , 0 )	

			}

		}else{

			if( k = Gui1.PressedControl ){
				; [ Pressed ]
				This.Gui1.DrawBitmap( cc.PressedImage , { X: cc.X , Y: cc.Y , W: cc.W , H: cc.H } , 0 , 0 )	

			}else if( k = Gui1.HoveredControl ){
				; [ Hovered ]
				This.Gui1.DrawBitmap( cc.HoveredImage , { X: cc.X , Y: cc.Y , W: cc.W , H: cc.H } , 0 , 0 )

			}else{
				; [ Default ]
				This.Gui1.DrawBitmap( cc.DefaultImage , { X: cc.X , Y: cc.Y , W: cc.W , H: cc.H } , 0 , 0 )

			}
		}
		
	}
	
	Gui1.UpdateWindow()
	
}




how can I make clicking the button run a specific routine?
For example,
Click Button 1, Send 1
Click Button 2, Send 2
That's not how radio controls normally work.
You would usually try to preform an action and look to see if a radio is selected or not.

If I wanted to make it so that if the first button is toggled on, when I press the up arrow key it would move my cursor to 100*100
If the first button isn't toggled, pressing the up arrow key would do whatever it normally would.

Code: Select all

;###################################################################

#If ( Gui1.SelectedControl = "Button_1" )  ;Defines the start of a context sensitive hotkey / hotstrings section. 

	Up::
		MouseMove, 100 , 100 
		return


#If ;end of section

;###################################################################
Or if I wanted to use it in another label

Code: Select all

;###################################################################
SomeOtherLabelTriggeredBySomethingElse:
	
	;You can also use a "Switch/Case" *See Docs*
	
	if( Gui1.SelectedControl = "Button_1" ){
	
		msgbox, Hello World
		
	}else if( Gui1.SelectedControl = "Button_2" ){
	
		Tooltip, Hello World
		
	}else{
	
		SoundBeep, 500 , 500
		
	}
	return
;###################################################################	
If on the other hand you are trying to toggle another image or window or something like that and want the action to take place right away, then all you need to do is either add a gosub to the toggleState label, or edit in what you want to do directly to the toggle label.
Another thing that you can do is have a different function for each of the radios. ( i.e. change the function for them in "AddControls()" )

Example:

Code: Select all

;###################################################################
AnotherLabel:
	msgbox, in the label
	return

;###################################################################
ToggleState( Gui1 , hwnd ){
	SetTimer, WatchLeaveHover , Off
	sleep, 60
	Gui1.Busy := 1
	cc := Gui1.Handles[ hwnd ]
	Gui1.PressedControl := cc.Name
	DrawWindow( Gui1 )
	While( GetKeyState( "LButton" , "P" ) )
		Sleep, 30
	MouseGetPos,,,, ctrl , 2 
	Gui1.PressedControl := ""
	if( ctrl = hwnd ){
		if( cc.Name = Gui1.SelectedControl ){
		
			Gui1.SelectedControl := ""
			Gui1.HoveredControl := cc.Name
			
			;Nothing is currently selected. If I want to hide something or whatever I would add that here. 
			;*** Depending on what I need to happen, I would add this before or after the two lines above***
			
		}else{
			
			;One of the two radios are selected.
			Gui1.SelectedControl := cc.Name
			Gui1.HoveredControl := cc.Name
			
			if( Gui1.SelectedControl = "Button_1" ){

				MsgBox, Hello World
				
				;This will call up the other label, execute the code in that label and then jump back here and then go to the next line and continue.
				goSub, AnotherLabel 

			}else if( Gui1.SelectedControl = "Button_2" ){

				SoundBeep
				
				;This will allow this current thread to finish before calling a new thread via the timer.
				SetTimer, AnotherLabel , -60
			}
		}
	}else{
		;This happens if you press a button but move your cursor away from the button before releasing your mouse. i.e. cancel the action.
		Gui1.HoveredControl := ""
	}

	;Where you place these next 3 lines has to do with whether or not the action takes a long time to do or the order you want things to take place in. 
	;You may want to draw the window before your action. i.e. do the next three lines before you call the label.

	DrawWindow( Gui1 )
	Gui1.Busy := 0
	SetTimer, WatchLeaveHover , 60
}
;###################################################################

Thank you, I tried to figure this out myself without asking for further help but I've hit another wall :(
I hope that helps.
If you have any other questions feel free to ask.
scoobs525
Posts: 49
Joined: 19 Apr 2022, 16:39

Re: Requesting help with using Gdip to display several images that each change on mouse over

08 Aug 2023, 16:20

Hellbent wrote:
03 Aug 2023, 00:10
Here is the replacement code for the button graphics.

Replace these two functions ( and edit the paths to your images in the "AddControls" function ).

I wrote out the two buttons in different ways so that you can get a better sense of how things work. You can pick either approach, or a combo of both ( As is the case with the main window object [ Gui1 ] ).
I hope that helps.
If you have any other questions feel free to ask.
This is amazing, thank you!! The Gui now does everything I wanted and more :D and I've learnt enough in the process to tinker and expand upon it from here to use it for it's intended purpose.
You've been really helpful and it's super appreciated :clap:


Just out of curiosity, I've been experimenting with what functionality could be added. Mainly for practice and to get a better feel of what things are doing.

I wondered how you would go about adding the ability to double-click a selected button to trigger it's routine?

What I've done so far is move the " Gui1.SelectedControl := "" " line out of the ToggleState function and into the HideWindow hotkeys, so now the selected button is set back to default when the gui is closed, but otherwise remains selected on click unless a different selection is made

I've then added the below;

Code: Select all

#IfWinExist GUI_Testing
*~LButton:: ;Close GUI on Left click if no buttons are hovered over
If 	( Gui1.HoveredControl = "" ){
		Gui1.HideWindow()
		Gui1.SelectedControl := ""
		DrawWindow( Gui1 )
}
else if (A_ThisHotkey = A_PriorHotkey and A_TimeSincePriorHotkey < 300){
*SPACE:: ;If a button is selected, run the below button routine on Double-Click or SPACE
If 	( Gui1.SelectedControl = "Button_1" ){
		Gosub Button_1
}else if( Gui1.SelectedControl = "Button_2" ){
		Gosub Button_2
}
return
}
return
This calls the selected button's subroutine when I use Space or double-click and has the added benefit of allowing me to double-click any button to do this, selected or not, as the first click marks the button active and the second click still calls the subroutine perfectly.

The only issue I've found with this is that the mouse position on the second click is completely ignored. In practice, this doesn't really matter too often (but means that when selecting one button then quickly selecting another, or clicking a blank space to close the gui, both actions still trigger the original button) - but I did find it strange that a double-click only takes the first click position into account.

Is there a better way of achieving this that you know of? I did wonder if bringing back the MouseClickEvent function could be the answer, but I don't know how to limit that to a double-click

Of course you've already done plenty here! I just a thought I'd run it by you in case you already knew the answer

Thanks again!
User avatar
Hellbent
Posts: 2114
Joined: 23 Sep 2017, 13:34

Re: Requesting help with using Gdip to display several images that each change on mouse over

08 Aug 2023, 20:45

scoobs525 wrote:
08 Aug 2023, 16:20

I wondered how you would go about adding the ability to double-click a selected button to trigger it's routine?
The buttons are using text controls as their trigger so you can use A_GuiEvent to monitor for double clicks.
The problem with it is that you can't have it as one or the other.

Code: Select all


Gui, New, +AlwaysOnTop
Gui, Add, Text, w100 h100 border hwndControlHwnd gTest
Gui, Show,  
return
GuiClose:ExitApp

Test:
	if( A_GuiEvent = "DoubleClick" ){
		
		Tooltip, % A_GuiEvent
		
	}else{
		
		return
		
	}
	return





Is there a better way of achieving this that you know of?
I know that this isn't what you had in mind, but I would recommend that you just add context to the first click.
i.e. Hold shift or ctrl or alt when you click the button.

Code: Select all

ButtonLabel:
	if( GetKeyState( "ctrl" , "P" ) && GetKeyState( "Shift" , "P" ) ){
		Soundbeep, 500
	}else if( GetKeyState( "ctrl" , "P" ) ){
		Soundbeep, 600
		return ;<<<----  point of interest
	}else if( GetKeyState( "Shift" , "P" ) ){
		Soundbeep, 700
	}else{
		tooltip, no context 
	}
	;other stuff 
	;other stuff 
	;other stuff 
	;other stuff 
	return

scoobs525
Posts: 49
Joined: 19 Apr 2022, 16:39

Re: Requesting help with using Gdip to display several images that each change on mouse over

09 Aug 2023, 03:25

Hellbent wrote:
08 Aug 2023, 20:45

The buttons are using text controls as their trigger so you can use A_GuiEvent to monitor for double clicks.
The problem with it is that you can't have it as one or the other.

I know that this isn't what you had in mind, but I would recommend that you just add context to the first click.
i.e. Hold shift or ctrl or alt when you click the button.
Perfect, thanks a lot :)

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot], Marium0505 and 341 guests