Better understanding sliders

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Jose Hidalgo
Posts: 222
Joined: 07 Mar 2021, 07:44

Better understanding sliders

12 May 2021, 14:04

Hi everybody,

I'm trying to familiarize myself with sliders. Unfortunately the documentation isn't clear to me, and I haven't been able to find any video tutorial.

Here's my attempt :
  • Have 3 vertical sliders, positioned evenly on a GUI, and centered vs. the GUI's width
  • Display each slider's name at the bottom of every one
  • Control the 3 sliders with 6 hotkeys : hotkey1 = slider 1 up, hotkey2 = slider 1 down, and so on.
  • Every time a slider is modified, grab the corresponding lvl := %A_GuiControl% and display the slider's name and lvl value in a tooltip, also centered vs. the GUI's width
I've found this recent topic, where boiler gave a working solution for a multi-slider GUI : https://www.autohotkey.com/boards/viewtopic.php?p=397040#p397040
So I've tried to adapt it to my own needs :

Code: Select all

win = Multi-Slider Window

Fader1 := "NAME 1"
Fader2 := "NAME 2"
Fader3 := "NAME 3"

Gui, Color, 666666

Gui, Add, Slider, x40 y25 h100 w25 TickInterval3 Line3 Vertical Invert AltSubmit Range-6-6 vSlider1  ggo, 0
Gui, Add, Slider, % "x" 140 " y25 h100 w25 Vertical Invert AltSubmit Range-6-6 vSlider" 2 " ggo", 0
Gui, Add, Slider, % "x" 240 " y25 h100 w25 Vertical Invert AltSubmit Range-6-6 vSlider" 3 " ggo", 0

Gui, Add, Text, , %Fader1% %Fader2% %Fader3%
Gui, Show, w300 h150, Multi-Slider Test
Return

go:							; Subroutine for all sliders.
  Gui, Submit, NoHide
  lvl := %A_GuiControl%				; This needs to be the output from whichever slider is being used 
  setlevel(A_GuiControl,win,lvl)
Return

setlevel(control,window,level)
	{
	ToolTip, % control " : " level " dB", 100, 28
	; slider = Slider20WndClass%control%
	; SendMessage, 0x405, 1, %level%, %slider%, %window%, 
	; ControlSend, %slider%, {Right 1}, %window%
	}
	
GuiClose:
ExitApp
Slider1's syntax is different, I wanted to try to use two different syntaxes.

There are some things that I don't understand. For example in this syntax : Gui, Add, Slider, % "x" 140 " y25 h100 w25 Vertical Invert AltSubmit Range-6-6 vSlider" 2 " ggo", 0
  • The w25 seems to make no difference (I've tried w50 but the slider stays the same)
  • Same thing for the AltSubmit. I've read that "it tells the program to use Microsoft's GDIPlus.dll to load the image, which might result in a different appearance for GIF, BMP, and icon images", but it makes no difference at all in this case.
  • I don't understand the end part : vSlider" 2" ggo", 0
Plus some things don't work yet :
  • The 3 sliders aren't automatically centered vs. the GUI width (I've only done it manually with hardcoded x values)
  • I haven't been able to display each slider's name at the bottom of every one. I have tried the Buddy2 slider option with my defined variables (Fader1 to Fader3) but I haven't been able to make it work.
  • The tooltip isn't automatically centered either (which is a problem since the tooltip's width will depend on the slider's name (which I haven't been able to display either)
  • I haven't implemented the hotkeys yet (haven't figured out how to assign a hotkey to a specific slider).
I hope I can get some help to make me better understand how things work here. Thank you !
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

13 May 2021, 06:34

Jose Hidalgo wrote: The w25 seems to make no difference (I've tried w50 but the slider stays the same)
What are you expecting to be different when you change the width? The width of the control does change, which you can see by the dotted outline when it has focus, but that's not going to change the way the features of the slider itself are drawn.

Jose Hidalgo wrote: Same thing for the AltSubmit. I've read that "it tells the program to use Microsoft's GDIPlus.dll to load the image, which might result in a different appearance for GIF, BMP, and icon images", but it makes no difference at all in this case.
The documentation says that regarding Picture controls, not Sliders, and it would make sense that it is only applicable to Pictures.

Jose Hidalgo wrote: I don't understand the end part : vSlider" 2" ggo", 0
In the one I posted that you copied from, it was to allow a variable to be used where you have the number 2, like this:

Code: Select all

"...vSlider" A_Index " ggo"
But since you are not dynamically creating them (i.e., not using a variable there), you can just make it part of the string instead of concatenating the value 2:

Code: Select all

"...vSlider2 ggo"
The same goes for the x position values. There is no reason to break them up if you're going to hardcode values for them.

Jose Hidalgo wrote: The 3 sliders aren't automatically centered vs. the GUI width (I've only done it manually with hardcoded x values)
That's true. AHK doesn't have a built-in method for centering a number of controls across the width of a GUI. If you don't want to hardcode it in, you can put in some math to divide up the width of the GUI and use an expression for the x position of each control.

Jose Hidalgo wrote: I haven't been able to display each slider's name at the bottom of every one. I have tried the Buddy2 slider option with my defined variables (Fader1 to Fader3) but I haven't been able to make it work.
When you use the Buddy2 option, it says the variable you specify is to be the variable identifying the control that contains the label text you want displayed, like this:

Code: Select all

win = Multi-Slider Window

Fader1 := "NAME 1"
Fader2 := "NAME 2"
Fader3 := "NAME 3"

Gui, Color, 666666

Gui, Add, Text, vBottomText1, % Fader1
Gui, Add, Text, vBottomText2, % Fader2
Gui, Add, Text, vBottomText3, % Fader3
Gui, Add, Slider, x40 y25 h100 w25 TickInterval3 Line3 Vertical Invert Range-6-6 vSlider1  ggo Buddy2BottomText1, 0
Gui, Add, Slider, % "x140 y25 h100 w25 Vertical Invert Range-6-6 vSlider2 ggo Buddy2BottomText2", 0
Gui, Add, Slider, % "x240 y25 h100 w25 Vertical Invert Range-6-6 vSlider3 ggo Buddy2BottomText3", 0

Gui, Show, w300 h150, Multi-Slider Test
Return

go:							; Subroutine for all sliders.
  Gui, Submit, NoHide
  lvl := %A_GuiControl%				; This needs to be the output from whichever slider is being used 
  setlevel(A_GuiControl,win,lvl)
Return

setlevel(control,window,level)
	{
	ToolTip, % control " : " level " dB", 100, 28
	; slider = Slider20WndClass%control%
	; SendMessage, 0x405, 1, %level%, %slider%, %window%, 
	; ControlSend, %slider%, {Right 1}, %window%
	}
	
GuiClose:
ExitApp

Jose Hidalgo wrote: The tooltip isn't automatically centered either (which is a problem since the tooltip's width will depend on the slider's name (which I haven't been able to display either)
You can do some math to have it automatically centered based on the width of the GUI.

Jose Hidalgo wrote: I haven't implemented the hotkeys yet (haven't figured out how to assign a hotkey to a specific slider).
In what way are you wanting to use hotkeys? A pair of keys for each slider for up/down? You would have the subroutine for each hotkey change the associated value of the slider position using GuiControl.
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

13 May 2021, 06:47

As you may have seen from the version of the code I posted in the previous post, once you take out the unneeded concatenation in your Gui, Add, Slider commands, there isn't much gained when forcing expression syntax. You're just making it a big string and putting quotes around it. The reason for using an expression there is for when you want to incorporate math into the values, like the following which dynamically creates the 3 sliders in a loop:

Code: Select all

win = Multi-Slider Window

Fader1 := "NAME 1"
Fader2 := "NAME 2"
Fader3 := "NAME 3"

Gui, Color, 666666

loop, 3 {
	Gui, Add, Text, vBottomText%A_Index%, % Fader%A_Index%
	Gui, Add, Slider, % "x" 40 + 100 * (A_Index - 1) " y25 h100 w25 TickInterval3 Line3 Vertical Invert Range-6-6 vSlider" A_Index "  ggo Buddy2BottomText" A_Index, 0
}

Gui, Show, w300 h150, Multi-Slider Test
Return

go:							; Subroutine for all sliders.
  Gui, Submit, NoHide
  lvl := %A_GuiControl%				; This needs to be the output from whichever slider is being used 
  setlevel(A_GuiControl,win,lvl)
Return

setlevel(control,window,level)
	{
	ToolTip, % control " : " level " dB", 100, 28
	; slider = Slider20WndClass%control%
	; SendMessage, 0x405, 1, %level%, %slider%, %window%, 
	; ControlSend, %slider%, {Right 1}, %window%
	}
	
GuiClose:
ExitApp
Jose Hidalgo
Posts: 222
Joined: 07 Mar 2021, 07:44

Re: Better understanding sliders

13 May 2021, 11:39

Thank you boiler, that's much clearer :)
Yes, I understand that expression syntax isn't needed in my case for only 3 sliders. I'll rewrite the code.
I will also do some math for the slider centering, that won't be a problem.
Thank you for the Buddy2 tip, now I understand how it works.
I'll number my remaining comments if it makes it easier :

1. About the w25 , I had noticed the dotted outline. I was somehow hoping the slider itself would change too, but I guess that's decided by the system. Only some minor elements can be changed.
2. About AltSubmit, I know that's applicable to pictures. That's why I don't understand it being included in the Gui, Add, Slider command. Why ?
3. About the syntax, what does the final "ggo" part mean ? Is it just a string, or is it related to the go subroutine ? I'm sorry to ask, but it's not obvious to me. :oops:

I'd like to achieve something similar to this : https://i.ibb.co/YTbnM6Z/2021-05-13-18-23-55.png . The look of the slider isn't really important, but :
4. Is there a way to display the slider range ? For example in my case it's from -6 to +6, and I would like to display it at the right (or left, nevermind) of every slider, next to the Tick lines : +6 next to the top one, and -6 next to the bottom one. Maybe even 0 in the middle.
5. Is there a way to continuously display the slider value on top of it, and not only in a temporary tooltip ? (in my picture you'll see "0" as it's the current value)

6. As for the hotkeys, yes, that's exactly what I'd like to do : 2 hotkeys per slider (up/down). Could you show me an example of the required syntax for one hotkey, to move a given slider up for example, and to get the corresponding slider value into a variable ? I guess if I can get the value into a variable, then I can display that variable in the GUI, which would solve question 5.

Thanks for being so helpful, much appreciated.
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

13 May 2021, 12:08

Jose Hidalgo wrote: 2. About AltSubmit, I know that's applicable to pictures. That's why I don't understand it being included in the Gui, Add, Slider command. Why ?
Here is the documentation on the options for Slider controls. I don't see anything shown about AltSubmit. Where did you see it applying to Sliders?

Jose Hidalgo wrote: 3. About the syntax, what does the final "ggo" part mean ? Is it just a string, or is it related to the go subroutine ? I'm sorry to ask, but it's not obvious to me. :oops:
The g-option for a control stands for Gosub. It launches the subroutine or function identified when the user clicks on or changes the control. In this case, the subroutine identified after the g is go, hence ggo. I would have capitalized the label to make it gGo, but that's how the person I was helping had done it.

Jose Hidalgo wrote: 4. Is there a way to display the slider range ? For example in my case it's from -6 to +6, and I would like to display it at the right (or left, nevermind) of every slider, next to the Tick lines : +6 next to the top one, and -6 next to the bottom one. Maybe even 0 in the middle.
You could add Text controls to place labels next to the ends of your slider. Or you could use the Buddy options to place the numbers above and below the slider. I think that's what they were mainly intended for.

Jose Hidalgo wrote: 5. Is there a way to continuously display the slider value on top of it, and not only in a temporary tooltip ? (in my picture you'll see "0" as it's the current value)
See the ToolTip option in the Slider options.

Jose Hidalgo wrote: 6. As for the hotkeys, yes, that's exactly what I'd like to do : 2 hotkeys per slider (up/down). Could you show me an example of the required syntax for one hotkey, to move a given slider up for example, and to get the corresponding slider value into a variable ? I guess if I can get the value into a variable, then I can display that variable in the GUI, which would solve question 5.
The following adds hotkeys q/a, w/s, and e/d to increase/decrease each of the three sliders. See the GuiControl section on putting new contents into the control (the part for UpDown/Slider/Progress controls) for more info on this.

Code: Select all

win = Multi-Slider Window

Fader1 := "NAME 1"
Fader2 := "NAME 2"
Fader3 := "NAME 3"

Gui, Color, 666666

loop, 3 {
	Gui, Add, Text, vBottomText%A_Index%, % Fader%A_Index%
	Gui, Add, Slider, % "x" 40 + 100 * (A_Index - 1) " y25 h100 w25 TickInterval3 Line3 Vertical Invert Range-6-6 vSlider" A_Index "  ggo Buddy2BottomText" A_Index, 0
}

Gui, Show, w300 h150, Multi-Slider Test
Return

go:							; Subroutine for all sliders.
  Gui, Submit, NoHide
  lvl := %A_GuiControl%				; This needs to be the output from whichever slider is being used 
  setlevel(A_GuiControl,win,lvl)
Return

setlevel(control,window,level)
	{
	ToolTip, % control " : " level " dB", 100, 28
	; slider = Slider20WndClass%control%
	; SendMessage, 0x405, 1, %level%, %slider%, %window%, 
	; ControlSend, %slider%, {Right 1}, %window%
	}
	
GuiClose:
ExitApp


q::
	Gui, Submit, NoHide
	GuiControl,, Slider1, +1
return

a::
	Gui, Submit, NoHide
	GuiControl,, Slider1, +-1
return

w::
	Gui, Submit, NoHide
	GuiControl,, Slider2, +1
return

s::
	Gui, Submit, NoHide
	GuiControl,, Slider2, +-1
return

e::
	Gui, Submit, NoHide
	GuiControl,, Slider3, +1
return

d::
	Gui, Submit, NoHide
	GuiControl,, Slider3, +-1
return
Jose Hidalgo
Posts: 222
Joined: 07 Mar 2021, 07:44

Re: Better understanding sliders

13 May 2021, 13:10

boiler wrote:
13 May 2021, 12:08
Here is the documentation on the options for Slider controls. I don't see anything shown about AltSubmit. Where did you see it applying to Sliders?
I saw it here, in the topic where you replied, it's in the two first posts : https://www.autohotkey.com/boards/viewtopic.php?p=397040#p397040
boiler wrote:
13 May 2021, 12:08
The g-option for a control stands for Gosub. It launches the subroutine or function identified when the user clicks on or changes the control. In this case, the subroutine identified after the g is go, hence ggo. I would have capitalized the label to make it gGo, but that's how the person I was helping had done it.
Oh boy, thanks for explaining this. I have trouble with abbreviations. "gosub go" or "gGo" I would have understood, lol. Lesson learned.
boiler wrote:
13 May 2021, 12:08
The following adds hotkeys q/a, w/s, and e/d to increase/decrease each of the three sliders. See the GuiControl section on putting new contents into the control (the part for UpDown/Slider/Progress controls) for more info on this.
Thank you for this. I'm going to study it and hopefully I'll come up with something. :thumbup:
I guess the setlevel function becomes unnecessary.
But I don't see how I could keep track of the current slider values, to use the 3 values in other functions. I could display such values on top using Buddy1, but how do I get them ?
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

13 May 2021, 13:42

Jose Hidalgo wrote: I saw it here, in the topic where you replied, it's in the two first posts : https://www.autohotkey.com/boards/viewtopic.php?p=397040#p397040
Yes, it was used for a Slider, but not for the reason you quoted. That was from the documentation on how it is used for a Picture control. To see what it does for a Slider control, see the explanation in the documentation for Slider controls.

Jose Hidalgo wrote: I guess the setlevel function becomes unnecessary.
It would still be useful if you wanted to do something when the user drags the slider, like displaying the ToolTip as it currently does.

Jose Hidalgo wrote: But I don't see how I could keep track of the current slider values, to use the 3 values in other functions. I could display such values on top using Buddy1, but how do I get them ?
After the Gui, Submit, NoHide line is executed, the variables associated with each slider (Slider1, Slider2, Slider3) contain the current values of the controls. If you want the value after it is changed, check it after the GuiControl line increases or decreases it. You can also get the value of any individual control at any time using GuiControlGet, even without a Gui, Submit, NoHide preceding it.
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

13 May 2021, 13:49

Jose Hidalgo wrote: Oh boy, thanks for explaining this. I have trouble with abbreviations. "gosub go" or "gGo" I would have understood, lol. Lesson learned.
Just to be clear, it stands for Gosub, but it's not an abbreviation in the sense that you can use either. You can't put the word Gosub in place of the g. It must be g immediately followed by the label of a subroutine or function, like gMySubroutine.
Jose Hidalgo
Posts: 222
Joined: 07 Mar 2021, 07:44

Re: Better understanding sliders

13 May 2021, 14:23

This updated code displays everything I need (almost), including the slider value on top (Buddy1).
But the values aren't updated. What am I missing ? :wtf: #justanotherbeginnersmistake

Code: Select all

win = Multi-Slider Window

Fader1 := "NAME 1"
Fader2 := "NAME 2"
Fader3 := "NAME 3"

Value1 := 0
Value2 := 0
Value3 := 0

DisplayGui(0, 0, 0)
return

DisplayGui(Value1, Value2, Value3)
{
  global
  Gui, Destroy
  Gui, Color, 666666
  Gui, Font, s14, Calibri

  loop, 3 {
    Gui, Add, Text, vTopText%A_Index%,    % Value%A_Index%
    Gui, Add, Text, vBottomText%A_Index%, % Fader%A_Index%
    Gui, Add, Slider, % "x" 40 + 100 * (A_Index - 1) " y25 h100 w25 TickInterval3 Line3 Vertical Invert Range-6-6 vSlider" A_Index "  ggo Buddy1TopText" A_Index " Buddy2BottomText" A_Index, 0
}

  Gui, Show, w300 h150, Multi-Slider Test
  Return

  go:						; Subroutine for all sliders.
    Gui, Submit, NoHide
    lvl := %A_GuiControl%		; This needs to be the output from whichever slider is being used 
    setlevel(A_GuiControl,win,lvl)
  Return
}

setlevel(control,window,level)
{
  global
  ToolTip, % control " : " level " dB", 100, 28
; slider = Slider20WndClass%control%
; SendMessage, 0x405, 1, %level%, %slider%, %window%, 
; ControlSend, %slider%, {Right 1}, %window%
}
	
GuiClose:
ExitApp

#a::
  Gui, Submit, NoHide
  GuiControl,, Slider1, +1
return

#q::
  Gui, Submit, NoHide
  GuiControl,, Slider1, +-1
return

#z::
  Gui, Submit, NoHide
  GuiControl,, Slider2, +1
return

#s::
  Gui, Submit, NoHide
  GuiControl,, Slider2, +-1
return

#e::
  Gui, Submit, NoHide
  GuiControl,, Slider3, +1
return

#d::
  Gui, Submit, NoHide
  GuiControl,, Slider3, +-1
return

#c:: ExitApp
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

13 May 2021, 17:44

It’s like I described, you just need to have it get the values of the variables associated with the sliders using Gui, Submit, NoHide (not by making the function global), then use GuiControl to put those the values into the text controls that are at the top of the sliders:

Code: Select all

win = Multi-Slider Window

Fader1 := "NAME 1"
Fader2 := "NAME 2"
Fader3 := "NAME 3"

Value1 := 0
Value2 := 0
Value3 := 0

DisplayGui(0, 0, 0)
return

DisplayGui(Value1, Value2, Value3)
{
  global
  Gui, Destroy
  Gui, Color, 666666
  Gui, Font, s14, Calibri

  loop, 3 {
    Gui, Add, Text, vTopText%A_Index% w20,    % Value%A_Index%
    Gui, Add, Text, vBottomText%A_Index%, % Fader%A_Index%
    Gui, Add, Slider, % "x" 40 + 100 * (A_Index - 1) " y25 h100 w25 TickInterval3 Line3 Vertical Invert Range-6-6 vSlider" A_Index "  ggo Buddy1TopText" A_Index " Buddy2BottomText" A_Index, 0
}

  Gui, Show, w300 h150, Multi-Slider Test
  Return

  go:						; Subroutine for all sliders.
    Gui, Submit, NoHide
    lvl := %A_GuiControl%		; This needs to be the output from whichever slider is being used 
    setlevel(A_GuiControl,win,lvl)
  Return
}

setlevel(control,window,level)
{
  Gui, Submit, NoHide
  loop, 3
    GuiControl,, TopText%A_Index%, % Slider%A_Index%
  ToolTip, % control " : " level " dB", 100, 28
; slider = Slider20WndClass%control%
; SendMessage, 0x405, 1, %level%, %slider%, %window%, 
; ControlSend, %slider%, {Right 1}, %window%
}
	
GuiClose:
ExitApp

#a::
  Gui, Submit, NoHide
  GuiControl,, Slider1, +1
return

#q::
  Gui, Submit, NoHide
  GuiControl,, Slider1, +-1
return

#z::
  Gui, Submit, NoHide
  GuiControl,, Slider2, +1
return

#s::
  Gui, Submit, NoHide
  GuiControl,, Slider2, +-1
return

#e::
  Gui, Submit, NoHide
  GuiControl,, Slider3, +1
return

#d::
  Gui, Submit, NoHide
  GuiControl,, Slider3, +-1
return

#c:: ExitApp
Jose Hidalgo
Posts: 222
Joined: 07 Mar 2021, 07:44

Re: Better understanding sliders

13 May 2021, 21:35

Thanks ! OK, I've added some minor stuff, and this is starting to look like what I'd want :) (FYI I've reconfigured the hotkeys for my keyboard which is AZERTY - it's not important, I just thought I should tell you)

Code: Select all

win = Multi-Slider Window

global SliNum  := 5

global SliVal1
global SliVal2
global SliVal3
global SliVal4
global SliVal5

SliName1 := "NAME 1"
SliName2 := "NAME 2"
SliName3 := "NAME 3"
SliName4 := "NAME 4"
SliName5 := "NAME 5"

SliCol1 := "CCCCCC"
SliCol2 := "FF9966"
SliCol3 := "66FF99"
SliCol4 := "FFAA66"
SliCol5 := "DDFF66"

Gui, Color, 666666
Gui, Font, s14, Calibri

loop, %SliNum%
{
  SliVal%A_Index% := 0
  Gui, Add, Text, vTopText%A_Index% cSliCol%A_Index% Center w50, % SliVal%A_Index% . " dB"
  Gui, Add, Text, vBottomText%A_Index% cSliCol%A_Index%, % SliName%A_Index%
  Gui, Add, Slider, % "x" 40 + 100 * (A_Index - 1) " y25 h100 w25 TickInterval3 Line3 Vertical Invert Range-6-6 vSliVal" A_Index "  ggo Buddy1TopText" A_Index " Buddy2BottomText" A_Index, 0
}

Gui, Show, w500 h150, Multi-Slider Test
Return

go:					; Subroutine for all sliders.
  Gui, Submit, NoHide
  lvl := %A_GuiControl%		; This needs to be the output from whichever slider is being used 
  SetLevel(A_GuiControl, win, lvl)
Return

SetLevel(Control, Window, Level)
{
  Gui, Submit, NoHide
  loop, %SliNum%
    GuiControl,, TopText%A_Index%, % SliVal%A_Index% . " dB"
;   ToolTip, % Control " : " Level " dB", 100, 28
;   Slider = Slider20WndClass%control%
;   SendMessage, 0x405, 1, %Level%, %Slider%, %Window%, 
;   ControlSend, %Slider%, {Right 1}, %Window%
}

ShowValues()
{
MsgBox, %SliVal1% | %SliVal2% | %SliVal3% | %SliVal4% | %SliVal5%
}

	
GuiClose:
ExitApp

#x:: ShowValues()

#a::
  Gui, Submit, NoHide
  GuiControl,, SliVal1, +3
return

#q::
  Gui, Submit, NoHide
  GuiControl,, SliVal1, +-3
return

#z::
  Gui, Submit, NoHide
  GuiControl,, SliVal2, +3
return

#s::
  Gui, Submit, NoHide
  GuiControl,, SliVal2, +-3
return

#e::
  Gui, Submit, NoHide
  GuiControl,, SliVal3, +3
return

#d::
  Gui, Submit, NoHide
  GuiControl,, SliVal3, +-3
return

#c:: ExitApp
Now here are the remaining questions :
  1. I've tried to introduce some color variables to have each slider's text (up and down) in a different color. I thought that by introducing such colors in the loop via cSliCol%A_Index% for both the top text and the bottom text it would work, but it doesn't.
  2. Each hotkey press increases/decreases the corresponding value by +3/-3. Also, TickInterval3 and Line3 are set, so all is good. However, if I grab the slider's cursor with the mouse, I have access to +1/-1 increments, which is unwanted. How could I limit increments to +3/-3, even with the mouse ?
  3. By default, Up/Down arrows are assigned to the active slider. Would it be possible to assign Left/Right arrows to changing the active slider ? Slider1 is default, so RIght arrow would activate Slider2, then Left arrow would activate Slider1 again, etc.
  4. I thought that for each hotkey, instead of having Gui, Submit, NoHide plus GuiControl,, SliVal1, +3 plus return, I could just call a function. But that doesn't work either. This was my failed intent for example :

    Code: Select all

    ShowValues(Num, Val)
    {
      Gui, Submit, NoHide
      GuiControl,, SliVal%Num%, Val
      MsgBox, %SliVal1% | %SliVal2% | %SliVal3% | %SliVal4% | %SliVal5%
      return
    }
    
    ; #a:: ShowValues(1, "+3")
I still have a lot to learn about controls...
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

14 May 2021, 04:27

Jose Hidalgo wrote: I've tried to introduce some color variables to have each slider's text (up and down) in a different color. I thought that by introducing such colors in the loop via cSliCol%A_Index% for both the top text and the bottom text it would work, but it doesn't.
You aren't getting the value of the variable because you don't have % around the whole variable, and to do so with the A_Index as well requires using another variable that you can assign right before it so then you can put % around the new variable's name. When you do this, it will show the text in the desired colors:

Code: Select all

  ThisCol := SliCol%A_Index%
  Gui, Add, Text, vTopText%A_Index% c%ThisCol% Center w50, % SliVal%A_Index% . " dB"
  Gui, Add, Text, vBottomText%A_Index% c%ThisCol%, % SliName%A_Index%

Jose Hidalgo wrote: Each hotkey press increases/decreases the corresponding value by +3/-3. Also, TickInterval3 and Line3 are set, so all is good. However, if I grab the slider's cursor with the mouse, I have access to +1/-1 increments, which is unwanted. How could I limit increments to +3/-3, even with the mouse ?
If you only ever want 5 total positions (-6, -3, 0, 3, 6), then change the range of your sliders to be -2 to 2, and the variables associated with them would just be an intermediate value which you would then multiply by 3 in a new variable to get -6, -3, 0, -3 and -6 before displaying it or otherwise using it.

Jose Hidalgo wrote: By default, Up/Down arrows are assigned to the active slider. Would it be possible to assign Left/Right arrows to changing the active slider ? Slider1 is default, so RIght arrow would activate Slider2, then Left arrow would activate Slider1 again, etc.
You could set hotkeys for the left and right arrow keys to change which slider has focus using GuiControl, Focus. You'll need a little bit of logic in those hotkey routines so that it will wrap around if the user presses Left when it's already at the first slider, then it will focus on the third one (and the same if they press Right when on the third one), if that's how you'd want it to work.

By the way, you probably should make it so the hotkeys are only active when this GUI is the active window, which you can do by adding the line #If WinActive("ahk_id " GuiID) before the first hotkey (currently #x::) and add the line Gui, +HwndGuiID before the Gui, Color line. That way they'll all work as normal when another program's window is the active window, which would be especially important if you made the hotkeys out of the arrow keys.

Jose Hidalgo wrote: I thought that for each hotkey, instead of having Gui, Submit, NoHide plus GuiControl,, SliVal1, +3 plus return, I could just call a function. But that doesn't work either. This was my failed intent for example :

Code: Select all

ShowValues(Num, Val)
{
  Gui, Submit, NoHide
  GuiControl,, SliVal%Num%, Val
  MsgBox, %SliVal1% | %SliVal2% | %SliVal3% | %SliVal4% | %SliVal5%
  return
}

; #a:: ShowValues(1, "+3")
Something like this?:

Code: Select all

win = Multi-Slider Window

global SliNum  := 5

global SliVal1
global SliVal2
global SliVal3
global SliVal4
global SliVal5

SliName1 := "NAME 1"
SliName2 := "NAME 2"
SliName3 := "NAME 3"
SliName4 := "NAME 4"
SliName5 := "NAME 5"

SliCol1 := "CCCCCC"
SliCol2 := "FF9966"
SliCol3 := "66FF99"
SliCol4 := "FFAA66"
SliCol5 := "DDFF66"

Gui, +HwndGuiID
Gui, Color, 666666
Gui, Font, s14, Calibri

loop, %SliNum%
{
  SliVal%A_Index% := 0
  ThisCol := SliCol%A_Index%
  Gui, Add, Text, vTopText%A_Index% c%ThisCol% Center w50, % SliVal%A_Index% . " dB"
  Gui, Add, Text, vBottomText%A_Index% c%ThisCol%, % SliName%A_Index%
  Gui, Add, Slider, % "x" 40 + 100 * (A_Index - 1) " y25 h100 w25 TickInterval3 Line3 Vertical Invert Range-6-6 vSliVal" A_Index "  ggo Buddy1TopText" A_Index " Buddy2BottomText" A_Index, 0
}

Gui, Show, w500 h150, Multi-Slider Test
Return

go:					; Subroutine for all sliders.
  Gui, Submit, NoHide
  lvl := %A_GuiControl%		; This needs to be the output from whichever slider is being used 
  SetLevel(A_GuiControl, win, lvl)
Return

SetLevel(Control, Window, Level)
{
  Gui, Submit, NoHide
  loop, %SliNum%
    GuiControl,, TopText%A_Index%, % SliVal%A_Index% . " dB"
;   ToolTip, % Control " : " Level " dB", 100, 28
;   Slider = Slider20WndClass%control%
;   SendMessage, 0x405, 1, %Level%, %Slider%, %Window%, 
;   ControlSend, %Slider%, {Right 1}, %Window%
}

ShowValues(Num, Val)
{
  GuiControl,, SliVal%Num%, % "+" Val
  Gui, Submit, NoHide
  loop, %SliNum%
    GuiControl,, TopText%A_Index%, % SliVal%A_Index% . " dB"
  return
}
	
GuiClose:
ExitApp

#If WinActive("ahk_id " GuiID)

#a::ShowValues(1, 3)

#q::ShowValues(1, -3)

#z::ShowValues(2, 3)

#s::ShowValues(2, -3)

#e::ShowValues(3, 3)

#d::ShowValues(3, -3)

#c:: ExitApp
Jose Hidalgo
Posts: 222
Joined: 07 Mar 2021, 07:44

Re: Better understanding sliders

14 May 2021, 09:11

Gosh, I always feel that I am SO CLOSE, but just because of a damn % or anything like that, my whole script doesn't work. And quite often AHK doesn't display any error message, so I'm on my own. :?

I was afraid you'd tell me about the -2/+2 slider, because... that's already what I tried to do yesterday, and it didn't work :lol:
But I finally got it working. Well, almost everything. I've successfully implemented all the things you told me, and it works, with all the hotkeys, including the four arrows. So I'm making progress thanks to you. :)
The only thing that doesn't work is the mouse : it still displays -1/+1 values instead of -3/+3. See for yourself :

Code: Select all

win = Multi-Slider Window

global SliNum    := 5
global ActiveSli := 1

global SliVal1 := 0
global SliVal2 := 0
global SliVal3 := 0
global SliVal4 := 0
global SliVal5 := 0

SliName1 := "NAME 1"
SliName2 := "NAME 2"
SliName3 := "NAME 3"
SliName4 := "NAME 4"
SliName5 := "NAME 5"

SliCol1 := "CCCCCC"
SliCol2 := "FF9966"
SliCol3 := "66FF99"
SliCol4 := "FFAA66"
SliCol5 := "DDFF66"

Gui, +HwndGuiID
Gui, Color, 666666
Gui, Font, s14, Calibri

loop, %SliNum%
{
  ThisCol := SliCol%A_Index%
  SliDis%A_Index% := 0
  Gui, Add, Text, vTopText%A_Index% c%ThisCol% Center w50, % SliDis%A_Index% . " dB"
  Gui, Add, Text, vBottomText%A_Index% c%ThisCol%, % SliName%A_Index%
  Gui, Add, Slider, % "x" 40 + 100 * (A_Index - 1) " y25 h100 w25 TickInterval1 Line1 Vertical Invert Range-2-2 vSliVal" A_Index "  ggo Buddy1TopText" A_Index " Buddy2BottomText" A_Index, 0
}

Gui, Show, w500 h150, Multi-Slider Test
Return

go:					; Subroutine for all sliders.
  Gui, Submit, NoHide
  lvl := %A_GuiControl%		; This needs to be the output from whichever slider is being used 
  SetLevel(A_GuiControl, win, lvl)
Return

; ------------------------------------

SetLevel(Control, Window, Level)
{
  Gui, Submit, NoHide
  loop, %SliNum%
    GuiControl,, TopText%A_Index%, % SliVal%A_Index% . " dB"
;   ToolTip, % Control " : " Level " dB", 100, 28
;   Slider = Slider20WndClass%control%
;   SendMessage, 0x405, 1, %Level%, %Slider%, %Window%, 
;   ControlSend, %Slider%, {Right 1}, %Window%
}

; ------------------------------------

ChangeVal(Num, Val)
{
  If (Num = 0)
    Num := ActiveSli
  GuiControl,, SliVal%Num%, % "+" Val
  Gui, Submit, NoHide
  SliDis%Num% := SliVal%Num% * 3
  loop, %SliNum%
    GuiControl,, TopText%A_Index%, % SliDis%A_Index% . " dB"
  return
}

; ------------------------------------

ChangeSli(Num)
{
  ActiveSli := ActiveSli + Num
  If (ActiveSli < 1)
    ActiveSli := 1
  If (ActiveSli > SliNum)
    ActiveSli := SliNum
  Gui, Submit, NoHide
  GuiControl, Focus, SliVal%ActiveSli%
  return
}

; ------------------------------------

GuiClose:
ExitApp

#If WinActive("ahk_id " GuiID)

Right::ChangeSli(1)
Left::ChangeSli(-1)

Up::ChangeVal(0, 1)
Down::ChangeVal(0, -1)

#a::ChangeVal(1, 1)
#q::ChangeVal(1, -1)

#z::ChangeVal(2, 1)
#s::ChangeVal(2, -1)

#e::ChangeVal(3, 1)
#d::ChangeVal(3, -1)

#c:: ExitApp
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

14 May 2021, 09:34

Jose Hidalgo wrote: The only thing that doesn't work is the mouse : it still displays -1/+1 values instead of -3/+3.
It just needs a * 3 in this line in the SetLevel function:

Code: Select all

    GuiControl,, TopText%A_Index%, % SliVal%A_Index% * 3 . " dB"
Jose Hidalgo
Posts: 222
Joined: 07 Mar 2021, 07:44

Re: Better understanding sliders

14 May 2021, 11:05

Almost there (it was a syntax problem again, now corrected). This one works perfectly, except when we mix mouse and hotkeys.
When hotkeys (letters or arrows) are used, I correctly set the ActiveSli variable to the currently active slider number. That part works.
When the mouse is used, that variable isn't modified. So if I press Up or Down AFTER using the mouse on a different slider, the wrong slider reacts.
So I guess there's something missing within the SetLevel function. But that function seems to work differently from the two functions that I created. It's the one that's been puzzling me from the start.
I don't know to detect the slide that's been selected by the mouse, in order to set the ActiveSli variable to the correct value.

Code: Select all

win = Multi-Slider Window

global SliNum    := 5
global ActiveSli := 1

global SliVal1 := 0
global SliVal2 := 0
global SliVal3 := 0
global SliVal4 := 0
global SliVal5 := 0

SliName1 := "NAME 1"
SliName2 := "NAME 2"
SliName3 := "NAME 3"
SliName4 := "NAME 4"
SliName5 := "NAME 5"

SliCol1 := "CCCCCC"
SliCol2 := "FF9966"
SliCol3 := "66FF99"
SliCol4 := "FFAA66"
SliCol5 := "DDFF66"

Gui, +HwndGuiID
Gui, Color, 666666
Gui, Font, s14, Calibri

loop, %SliNum%
{
  ThisCol := SliCol%A_Index%
  SliDis%A_Index% := 0
  Gui, Add, Text, vTopText%A_Index% c%ThisCol% Center w50, % SliDis%A_Index% . " dB"
  Gui, Add, Text, vBottomText%A_Index% c%ThisCol%, % SliName%A_Index%
  Gui, Add, Slider, % "x" 40 + 100 * (A_Index - 1) " y25 h100 w25 TickInterval1 Line1 Vertical Invert Range-2-2 vSliVal" A_Index "  ggo Buddy1TopText" A_Index " Buddy2BottomText" A_Index, 0
}

Gui, Show, w500 h150, Multi-Slider Test
Return

go:					; Subroutine for all sliders.
  Gui, Submit, NoHide
  lvl := %A_GuiControl%		; This needs to be the output from whichever slider is being used 
  SetLevel(A_GuiControl, win, lvl)
Return

; ------------------------------------

SetLevel(Control, Window, Level)
{
  Gui, Submit, NoHide
  loop, %SliNum%
  {
    SliDis%A_Index% := SliVal%A_Index% * 3
    GuiControl,, TopText%A_Index%, % SliDis%A_Index% . " dB"
  }
  return
}

; ------------------------------------

ChangeVal(Num, Val)
{
  If (Num = 0)
    Num := ActiveSli
  GuiControl,, SliVal%Num%, % "+" Val
  Gui, Submit, NoHide
  SliDis%Num% := SliVal%Num% * 3
  loop, %SliNum%
    GuiControl,, TopText%A_Index%, % SliDis%A_Index% . " dB"
  return
}

; ------------------------------------

ChangeSli(Num)
{
  ActiveSli := ActiveSli + Num
  If (ActiveSli < 1)
    ActiveSli := 1
  If (ActiveSli > SliNum)
    ActiveSli := SliNum
  Gui, Submit, NoHide
  GuiControl, Focus, SliVal%ActiveSli%
  return
}

; ------------------------------------

GuiClose:
ExitApp

#If WinActive("ahk_id " GuiID)

Right::ChangeSli(1)
Left::ChangeSli(-1)

Up::ChangeVal(0, 1)
Down::ChangeVal(0, -1)

#a::ChangeVal(1, 1)
#q::ChangeVal(1, -1)

#z::ChangeVal(2, 1)
#s::ChangeVal(2, -1)

#e::ChangeVal(3, 1)
#d::ChangeVal(3, -1)

#c:: ExitApp
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

14 May 2021, 12:15

The variable Control in the SetLevel function contains the control that was changed, so you just need to get the number from the end of that control name. Add this as the first line in that function:

Code: Select all

  ActiveSli := SubStr(Control, 0)
Jose Hidalgo
Posts: 222
Joined: 07 Mar 2021, 07:44

Re: Better understanding sliders

14 May 2021, 13:15

Works perfectly now ! Big thanks once again ! :bravo:

Code: Select all

win = Multi-Slider Window

global SliNum    := 5
global ActiveSli := 1

global SliVal1 := 0
global SliVal2 := 0
global SliVal3 := 0
global SliVal4 := 0
global SliVal5 := 0

SliName1 := "NAME 1"
SliName2 := "NAME 2"
SliName3 := "NAME 3"
SliName4 := "NAME 4"
SliName5 := "NAME 5"

SliCol1 := "CCCCCC"
SliCol2 := "FF9966"
SliCol3 := "66FF99"
SliCol4 := "FFAA66"
SliCol5 := "DDFF66"

Gui, +HwndGuiID
Gui, Color, 666666
Gui, Font, s14, Calibri

loop, %SliNum%
{
  ThisCol := SliCol%A_Index%
  SliDis%A_Index% := 0
  Gui, Add, Text, vTopText%A_Index% c%ThisCol% Center w50, % SliDis%A_Index% . " dB"
  Gui, Add, Text, vBottomText%A_Index% c%ThisCol%, % SliName%A_Index%
  Gui, Add, Slider, % "x" 40 + 100 * (A_Index - 1) " y25 h100 w25 TickInterval1 Line1 Vertical Invert Range-2-2 vSliVal" A_Index "  ggo Buddy1TopText" A_Index " Buddy2BottomText" A_Index, 0
}

Gui, Show, w500 h150, Multi-Slider Test
Return

go:					; Subroutine for all sliders.
  Gui, Submit, NoHide
  lvl := %A_GuiControl%		; This needs to be the output from whichever slider is being used 
  SetLevel(A_GuiControl, win, lvl)
Return

; ------------------------------------

SetLevel(Control, Window, Level)
{
  ActiveSli := SubStr(Control, 0)
  Gui, Submit, NoHide
  loop, %SliNum%
  {
    SliDis%A_Index% := SliVal%A_Index% * 3
    GuiControl,, TopText%A_Index%, % SliDis%A_Index% . " dB"
  }
  return
}

; ------------------------------------

ChangeVal(Num, Val)
{
  If (Num = 0)
    Num := ActiveSli
  GuiControl,, SliVal%Num%, % "+" Val
  Gui, Submit, NoHide
  SliDis%Num% := SliVal%Num% * 3
  loop, %SliNum%
    GuiControl,, TopText%A_Index%, % SliDis%A_Index% . " dB"
  return
}

; ------------------------------------

ChangeSli(Num)
{
  ActiveSli := ActiveSli + Num
  If (ActiveSli < 1)
    ActiveSli := 1
  If (ActiveSli > SliNum)
    ActiveSli := SliNum
  Gui, Submit, NoHide
  GuiControl, Focus, SliVal%ActiveSli%
  return
}

; ------------------------------------

GuiClose:
ExitApp

#If WinActive("ahk_id " GuiID)

Right::ChangeSli(1)
Left::ChangeSli(-1)

Up::ChangeVal(0, 1)
Down::ChangeVal(0, -1)

#a::ChangeVal(1, 1)
#q::ChangeVal(1, -1)

#z::ChangeVal(2, 1)
#s::ChangeVal(2, -1)

#e::ChangeVal(3, 1)
#d::ChangeVal(3, -1)

#c:: ExitApp
Now let's see what I can do with this new knowledge. Fingers crossed !
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

14 May 2021, 13:56

Glad to help. Good luck with the project!
Jose Hidalgo
Posts: 222
Joined: 07 Mar 2021, 07:44

Re: Better understanding sliders

15 May 2021, 10:19

Thank you very much boiler :) I'm posting here because it's really closely related.
I'm trying to integrate this into a larger function. Thanks to you, I realize that I may now change the behaviour of my whole script ! :shock:
You see, until now, I was basically creating a GUI, displaying some variables in it, then every time a variable changed, I just destroyed the GUi and rebuilt it. :mrgreen: It worked, but it was probably overkill.
Now thanks to the wonders of GUI controls, I guess I could just create the GUI once and for all, and just assign the displayed variables to a control subroutine like we just did with sliders.
Then I would only have to use the SetControl(Control) function to magically update the GUI without destroying/rebuilding it, right ? That would be much smarter ! :D

Here's the part of the code I'm working on, no hotkeys yet :

Code: Select all

DisplayGui(Listener, EQColor, EQText, HSVColor, HSVText)		; Displays the relevant GUI
{
  global
  guiName := Listener "Gui"
  Gui, %guiName%: +OwnDialogs
  Gui, %guiName%: -Caption +ToolWindow AlwaysOnTop
  Gui, %guiName%: Color, %BackColor%
  Gui, %guiName%: Margin, 8, 0
  
  ; ---------- Part 1 - Creates a first line of text with four variables : EQColor, EQText, HSVColor and HSVTexwt ----------
  ; ---------- The line is cut into 3 sections in order to display 3 different colors ----------
  
  Gui, %guiName%: Font, s%TextSize%, %TextFont%
  Gui, %guiName%: Add, Text, Section c%EQColor%, %EQText%
  If (UseHSV = "1")
  {
    Gui, %guiName%: Add, Text, Section ys, +
    Gui, %guiName%: Add, Text, Section ys c%HSVColor%, %HSVText%
  }

; ---------- Part 2 - Creates the 5 sliders we have been discussing in this topic ----------

  Gui, %guiName%: Font, s14, %TextFont%
  loop, %SliNum%
  {
    ThisCol := SliCol%A_Index%
    Gui, %guiName%: Add, Text, vTopText%A_Index% c%ThisCol% Center w50, % SliDis%A_Index% . " dB"
    Gui, %guiName%: Add, Text, vBottomText%A_Index% c%ThisCol%, % SliName%A_Index%
    Gui, %guiName%: Add, Slider, % "x" 27 + 75 * (A_Index - 1) " y70 h80 w25 TickInterval1 Line1 Vertical Invert Range-2-2 vSliVal" A_Index "  gGo Buddy1TopText" A_Index " Buddy2BottomText" A_Index, 0
  }

; ---------- Part 3 - Finally shows the GUI ----------

  ShowGui(Listener)
  return

; ---------- Go subroutine ----------

  Go:
    Gui, %guiName%: Submit, NoHide
    SetControl(A_GuiControl)
    return

  return
}

; ---------- SetControl ----------

SetControl(Control)
{
  guiName := Listener "Gui"
  Gui, %guiName%: Submit, NoHide
  ActiveSli := SubStr(Control, 0)
  loop, %SliNum%
  {
    SliDis%A_Index% := SliVal%A_Index% * 3
    GuiControl,, TopText%A_Index%, % SliDis%A_Index% . " dB"
  }
  Enhancer()
  return
}
Part 2 is already OK : sliders are created like you just showed me, and the Go subroutine is called accordingly.
What I would need to do now is :
  • Do the same thing for Part 1, but I can't figure out how to call the Go subroutine for the Add, Text lines.
  • Modify the SetControl function, in order to not only update the sliders, but update the first line of text as well.
Is this as easy to implement as I suspect ? If so, I am going to learn a lot from this for future scripts ! :D
User avatar
boiler
Posts: 16705
Joined: 21 Dec 2014, 02:44

Re: Better understanding sliders

15 May 2021, 12:24

Jose Hidalgo wrote: Then I would only have to use the SetControl(Control) function to magically update the GUI without destroying/rebuilding it, right ?
In general, yes, it’s often easier to just update the GUI rather than to rebuild it from scratch, especially if you’re trying to leave a lot of its contents intact.

Jose Hidalgo wrote: I can't figure out how to call the Go subroutine for the Add, Text lines.
Do you mean you want the Go subroutine to be executed when the user clicks on those text controls? If so, you would add gGo to the options for each of those controls.

Jose Hidalgo wrote: Modify the SetControl function, in order to not only update the sliders, but update the first line of text as well.
To update the text, then you need to associate a variable with that control by using the v option, such as vText1, and you would update its contents using GuiControl like this:

Code: Select all

GuiControl,, Text1, New text
Make sure you set the width of the text controls initially so they are wide enough to contain whatever text they may contain without cutting it off.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Google [Bot], Shifted_Right and 164 guests