AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Flexible Gui Up Down control

 
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
PhiLho



Joined: 27 Dec 2005
Posts: 6836
Location: France (near Paris)

PostPosted: Tue Aug 29, 2006 2:15 pm    Post subject: Flexible Gui Up Down control Reply with quote

[EDIT] numEric provided a much better version, which is referenced in the manual now. See Radio button to control number of loops and msgbox text for some reasons why it is better.
I left this because some techniques here can be interesting.

Recently, Torteth asked for more flexibility for the UpDown GUI control.
I came with a workaround that seems to be usable, but was hard-coded.

I tried to add a bit of flexibility and code-reuse.

There are still some constraints and limitations:

- These special controls must be created before any other Edit control. This limitation could be removed if we knew the ClassNN of a newly added control. Perhaps it is already possible.
[EDIT] I found how to remove this restriction! Yeah!

- I coded this only for the main GUI (no GUI number). Not a big problem, I think.

- The user can change the value to one that cannot be reached with the control. Eg., in my example, using the arrows you can get only even numbers, but if the user types an odd number, the progress will then go from one odd number to the next.
This can be actually an advantage, and it is easy to add, if necessary, code to check if the value is valid, otherwise to constrain it to legal values only.
Note that with a small hack, you can associate two up-down controls to an edit one, eg. one for coarse values, the other for finer values.

Here is the code, with a small example:
Code:
; Example of use

Gui Add, Edit, x10 y70 w250 h100, Just`nto test`nUp and Down`noutside a Fud.

; Current number of such controls
#fudControlNb := 0

?fudRangeLow := 0
?fudRangeHigh := 10
?fudIncrement := 0.1
?fudStartValue := 5
?fudXPos := 10
?fudYPos := 10
?fudWidth := 70
?fudVarName = firstUD
Gosub AddFlexibleUpDownControl

?fudRangeLow := -50
?fudRangeHigh := 50
?fudIncrement := 2
?fudStartValue := 0
?fudXPos := 10
?fudYPos := 40
?fudWidth := 50
?fudVarName = anotherUpDown
Gosub AddFlexibleUpDownControl


Gui Add, Button, x100 y180 w50 h25 gShowValues, OK
Gui +LastFound
guiID := WinExist()
Gui Show, w320, FlexibleGuiUpDown
Return

ShowValues:
   Loop %#fudControlNb%
   {
      v := #fudControlList?vn?%A_Index%
      GuiControlGet %v%
      v := %v%
      r = %r%UD%A_Index% = %v%`n
   }
   MsgBox %r%
Return

/*
Flexible Gui Up Down control
*/

; I prefix the volatile variables I use here with fud? and the persistant ones with #fud
; to avoid clashes with the variables of the host application.
; Also I prefix the parameters of the subroutine with ?fud.
; Alas, this makes the code quite obscure...

AddFlexibleUpDownControl:
   ; Store the parameters of the control
   #fudControlNb += 1
   #fudControlArray%#fudControlNb%?rangLow := ?fudRangeLow
   #fudControlArray%#fudControlNb%?rangHigh := ?fudRangeHigh
   #fudControlArray%#fudControlNb%?increment := ?fudIncrement
   ; Create the pseudo-buddy edit control, named as requested
   Gui Add, Edit, x%?fudXPos% y%?fudYPos% w%?fudWidth% h20 v%?fudVarName%, %?fudStartValue%
   px := ?fudXPos + ?fudWidth
   ; Create the up-down control on the right of the buddy
   Gui Add, UpDown, x%px% y%?fudYPos% w12 h24 Range-1-1 -16 gUDClick v[%?fudVarName%], 0
   ; Store lookup information
   #fudControlList?id?%?fudVarName% := #fudControlNb
   #fudControlList?vn?%#fudControlNb% := ?fudVarName
Return

UDClick:
   ; Which up-down control was clicked?
   fudVar?udVar := A_GuiControl
   fudVar?udValue := %fudVar?udVar% ; -1 or 1
   ; Remove [ and ] to get the control name
   StringTrimLeft fudVar?udVar, fudVar?udVar, 1
   StringTrimRight fudVar?udVar, fudVar?udVar, 1
   ; Get the control ID
   fudVar?controlNb := #fudControlList?id?%fudVar?udVar%
UDChange:
   ; Get value in the Edit control
   GuiControlGet %fudVar?udVar%
   ; Add (or substract) the increment
   fudVar?udValue := %fudVar?udVar% + fudVar?udValue * #fudControlArray%fudVar?controlNb%?increment
   ; Keep it within the bounds (no wrapping yet)
   If (fudVar?udValue < #fudControlArray%fudVar?controlNb%?rangLow)
      fudVar?udValue := #fudControlArray%fudVar?controlNb%?rangLow
   Else If (fudVar?udValue > #fudControlArray%fudVar?controlNb%?rangHigh)
      fudVar?udValue := #fudControlArray%fudVar?controlNb%?rangHigh
   ; Update the value in the Edit control
   GuiControl, , %fudVar?udVar%, %fudVar?udValue%
   ; And reset the UpDown control to the neutral position
   GuiControl, , [%fudVar?udVar%], 0
Return

~*Up::
~*Down::
   ; Get the variable name of the control with the focus
   GuiControlGet fudVar?udVar, FocusV
   fudVar?controlNb := 0
   ; Search if it is one of our flexible up down controls...
   Loop %#fudControlNb%
   {
      If (fudVar?udVar = #fudControlList?vn?%A_Index%)
      {
         ; Found!
         fudVar?controlNb := A_Index
         Break
      }
   }
   If (fudVar?controlNb > 0)
   {
      ; OK, that's one of our controls
      If (A_ThisHotkey = "~*Up")
         fudVar?udValue := 1
      Else
         fudVar?udValue := -1
      Goto UDChange
   }
Return

GuiClose:
GuiEscape:
ExitApp
I hope you will find this useful.
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Last edited by PhiLho on Mon Oct 09, 2006 11:41 am; edited 2 times in total
Back to top
View user's profile Send private message Visit poster's website
foom



Joined: 19 Apr 2006
Posts: 386

PostPosted: Tue Aug 29, 2006 8:11 pm    Post subject: Reply with quote

Hi philho,

Torteths thread caught my attention too since i am developing and frontend for H.264 encoding and would like to have updown controls which output floats since some of the commandline params the frontend passes to x264.exe are floats.

I apreciate your work on this but still think that this is a bunch of code and i think i might have and solution which would be easier to maintain.
Problem is that it demands to work with structures.
Now youre one of ahk's bitjugglers Smile and might tell me whats wrong with following code

Edit:
Found the error and reworked the script. Here you go.
Code:
#SingleInstance force

;"(ClassNN of the editcontrol which should have floats in it, found via windowspy)|(minvalue)|(maxvalue)|(steps)(`n)(NextEditsClassNN...)"
udEditList:="Edit1|10|50|0.25`nEdit2|-10|10|0.5"

;add the controls as usuall
Gui Add, Edit, w100 h20 vudedit,
Gui Add, UpDown,  w30 h24  vud , 23

Gui Add, Edit,  w100 h20 vudedit2,
Gui Add, UpDown,  w30 h24  vud2 , 5

Gui, Show

;look for the WM_NOTIFY message
OnMessage(0x4E, "WM_NOTIFY")
return

WM_NOTIFY(wParam, lParam)
{
    if (ExtractIntegerP(lParam,8,1) = -722)       ; if this is true a updowncontrol has send an UDN_DELTAPOS message
    {
        udHwnd:=ExtractIntegerP(lparam,0,0)
        iPos:=ExtractIntegerP(lparam,12,1)   
        iDelta:=ExtractIntegerP(lparam,16,1)

        SendMessage, 0x46A,,,, ahk_id %udHwnd%    ;gets the buddy of the updowncontrol that send the UDN_DELTAPOS message
        if (errorlevel)
        {
            udEditHwnd:=errorlevel
            udData:=GetudData(udEditHwnd,iDelta)  ;parse the udEditList and return the new value
            if udData = FAIL
                Return False                      ;the item was not found in the udEditList
            ControlSetText,, % udData , ahk_id %udEditHwnd%  ;set the new value in the editcontrol

            return True  ; indicates that the proposed change from the updowncontrol should be discarded
        }
        else
            return False ; don't discard the proposed change by the updowncontrol
    }

}

GetudData(_udEditHwnd,_delta)
{
    local udEditListItem, udEdithwnd, udEdit

    Loop, Parse, udEditList, `n, `n
    {
        StringSplit, udEditListItem, A_LoopField,|
        ControlGet, udEdithwnd, Hwnd,, %udEditListItem1%, A

        if (udEdithwnd = _udEdithwnd)
        {
            ControlGetText, udEdit,, ahk_id %udEditHwnd%
            udEdit+=udEditListItem4*_Delta

            if (udEdit < udEditListItem2)
                return udEditListItem2
            else if (udEdit > udEditListItem3)
                return udEditListItem3
            else
                return udEdit
        }
        else
            continue
    }
    Return "FAIL"
}

GuiClose:
ExitApp

ExtractIntegerP(ByRef pSource, pOffset = 0, pIsSigned = false, pSize = 4)
{
   Loop %pSize%
      result += *(pSource + pOffset + A_Index-1) << 8*(A_Index-1)
   if (!pIsSigned OR pSize > 4 OR result < 0x80000000)
      return result
   return -(0xFFFFFFFF - result + 1)
}

@Chris
If you read this, notice this is again an opurtunity for a Hwnd() function like discussed here because one could simply use the associated vVarNames instead of having to look up the ClassNN with WindowSpy.


Last edited by foom on Wed Aug 30, 2006 1:38 pm; edited 1 time in total
Back to top
View user's profile Send private message
PhiLho



Joined: 27 Dec 2005
Posts: 6836
Location: France (near Paris)

PostPosted: Wed Aug 30, 2006 1:37 pm    Post subject: Reply with quote

I like your way, it is good to have an alternative.

The good points:
- The controls are created in the classical way, using buddy.
- The code is indeed slightly clearer -- but of same size (if you remove the demo code in both versions).

The bad points:
- You still have to know in advance the classNN of the added controls... It is doable in GUIs, but not very friendly. Of course, it is more a limitation of AHK than a problem with your code.
- More annoying, but I suppose you can correct this: if you use the Up and Down keys in the edit control, as requested, the progress will still be 1 by 1, and starting at the initial default value...
- You parse the settings each time. I avoided this by putting them in arrays, at the cost of convoluted names... And frankly, the time spent on parsing is probably unoticeable.
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Back to top
View user's profile Send private message Visit poster's website
foom



Joined: 19 Apr 2006
Posts: 386

PostPosted: Wed Aug 30, 2006 1:43 pm    Post subject: Reply with quote

PhiLho wrote:

- More annoying, but I suppose you can correct this: if you use the Up and Down keys in the edit control, as requested, the progress will still be 1 by 1, and starting at the initial default value...


Ohh Snap!
Can you give me some advice?

BTW same goes for holding up or down pressed in the control which is the effekt of pressing the up or down key in the edit. I have no idea whats causing that.
Back to top
View user's profile Send private message
PhiLho



Joined: 27 Dec 2005
Posts: 6836
Location: France (near Paris)

PostPosted: Wed Aug 30, 2006 4:02 pm    Post subject: Reply with quote

I think that the problem is with the mysterious (undocumented) SendMessage 0x46A.
Either it fails and errorlevel is 0 and you return false (that's what I see with WinInspector), or the GetudData fails for the same result.
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Back to top
View user's profile Send private message Visit poster's website
foom



Joined: 19 Apr 2006
Posts: 386

PostPosted: Wed Aug 30, 2006 9:09 pm    Post subject: Reply with quote

PhiLho wrote:
I think that the problem is with the mysterious (undocumented) SendMessage 0x46A.
Either it fails and errorlevel is 0 and you return false (that's what I see with WinInspector), or the GetudData fails for the same result.


No that message is just for retrieving the ud's buddy UDM_GETBUDDY.
And it doesn't fail eighter doesn't GetudData fail.
I think it has something to do with UDM_SETACCEL which i think is responsible for the numbers getting in/decremented faster/(in bigger steps) the longer you keep up or down pressed.
Is there anywhere on the web the source of the updownclass i could have a look at? Because i can't find it in the includefiles of gcc.
Back to top
View user's profile Send private message
PhiLho



Joined: 27 Dec 2005
Posts: 6836
Location: France (near Paris)

PostPosted: Thu Aug 31, 2006 12:24 pm    Post subject: Reply with quote

foom wrote:
Is there anywhere on the web the source of the updownclass i could have a look at?
AFAIK, Windows' sources are quite secret, Microsoft hasn't completely gone the open source way... Smile

I looked again with Winspector Spy, when using the arrow key, the WM_NOTIFY message is sent, but not managed by the OnMessage (the function isn't called). Strange.
_________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")
Back to top
View user's profile Send private message Visit poster's website
foom



Joined: 19 Apr 2006
Posts: 386

PostPosted: Thu Aug 31, 2006 12:57 pm    Post subject: Reply with quote

Maybe Chris borked something with the last update...he did somethink to fix an onmessage bug. I found another bug with onmessage. See here
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Page 1 of 1

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group