AutoHotkey Community

It is currently May 27th, 2012, 9:33 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: August 29th, 2006, 3:15 pm 
Offline

Joined: December 27th, 2005, 1:46 pm
Posts: 6837
Location: France (near Paris)
[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.

_________________
Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Last edited by PhiLho on October 9th, 2006, 12:41 pm, edited 2 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 29th, 2006, 9:11 pm 
Offline

Joined: April 19th, 2006, 1:02 pm
Posts: 386
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 :) 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 August 30th, 2006, 2:38 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 30th, 2006, 2:37 pm 
Offline

Joined: December 27th, 2005, 1:46 pm
Posts: 6837
Location: France (near Paris)
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.

_________________
Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 30th, 2006, 2:43 pm 
Offline

Joined: April 19th, 2006, 1:02 pm
Posts: 386
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 30th, 2006, 5:02 pm 
Offline

Joined: December 27th, 2005, 1:46 pm
Posts: 6837
Location: France (near Paris)
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.

_________________
Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 30th, 2006, 10:09 pm 
Offline

Joined: April 19th, 2006, 1:02 pm
Posts: 386
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.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 31st, 2006, 1:24 pm 
Offline

Joined: December 27th, 2005, 1:46 pm
Posts: 6837
Location: France (near Paris)
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... :-)

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.

_________________
Image vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2")


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 31st, 2006, 1:57 pm 
Offline

Joined: April 19th, 2006, 1:02 pm
Posts: 386
Maybe Chris borked something with the last update...he did somethink to fix an onmessage bug. I found another bug with onmessage. See here


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: Google Feedfetcher, nomissenrojb, Stigg and 19 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group