Gui Edit Controls: Numbers/ 2 decimal /negative value for use in Money Calculation Table Topic is solved

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Gui Edit Controls: Numbers/ 2 decimal /negative value for use in Money Calculation Table

11 Sep 2018, 17:55

Hi guys,

I've been reading exemples on the AHK forums and archives.
Someone made a genious little gLabel to create an Edit Gui Control with this format: numbers only / decimal dot allowed / 2 decimal max

My question is: How to add the possibilities to allow negative sign at the beginning of the value??

like this: -10.50

Code: Select all

Gui, Add, Edit, x85 y10 w80 h20 hwndhMyText vMyText gOnChangeMyText +right 
Gui, Show
return

GuiClose:
ExitApp
return

OnChangeMyText:
Gui, Submit, NoHide 
if RegExMatch(MyText, "[^\d\.]|\..*\.|\.\d{3,}|^0$")   ; <<---------
{
	ControlGet, cursorPos, CurrentCol,, %MyText%, A ; Get current cursor position
	MyText:=Round(MyText,2)
	GuiControl, Text, MyText, %prevText% ; Write text back to Edit control
	cursorPos := cursorPos - 2 
	SendMessage, 0xB1, cursorPos, cursorPos,, ahk_id %hMyText% EM_SETSEL ; Add hwndh to Edit control for this to work
}
else
	prevText := MyText
return

I've been trying to add things in the regex detection but it doesnt work as intended.
Any help would eb appreciated :)

Edit: if someone can help me interpret the RegEx it help me figure out for next times. Its pretty confusing lol

thanks alot!



EDIT: After following the posts, I ended-up to another problem which is, how to calculate the Table Total values WHEN some of the values are empty!?
Doing the maths with integers mixed with empty strings will give error rather than 0 + integers
Image
Image
Last edited by DRocks on 02 Oct 2018, 22:26, edited 4 times in total.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 04:34

Try this:

Code: Select all

SetBatchLines, -1
Gui, Add, Edit, gForceNumber Right
Gui, Show



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
    local
    static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []

    ControlGet, Pos, CurrentCol,,, ahk_id %hEdit%
    GuiControlGet, NewNumber,, %hEdit%
    StrReplace(NewNumber, ".",, DotCount)
    Decimals := StrLen(StrSplit(NewNumber, ".").2)

    BAD := (NewNumber ~= BadNeedle)
        Or (DotCount > 1)
        Or (Decimals > maxDecimals)

    If (BAD) {
        ControlGetPos, x, y,,,, ahk_id %hEdit%
        ToolTip, %Warning%, x, y-20
        SetTimer, ForceNumber_ToolTipOff, -2000
        GuiControl,, %hEdit%, % PrevNumber[hEdit]
        SendMessage, 0xB1, % Pos-2, % Pos-2,, ahk_id %hEdit%
    }

    Else ; GOOD
        PrevNumber[hEdit] := NewNumber

    Return

    ForceNumber_ToolTipOff:
        ToolTip ; off
    Return
}
I hope that helps.
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 06:13

Hey Wolf_II!

Wow that's even greater! Your code is perfect man it does exactly what I'm looking for and is clear enough to easily modify.
Thanks alot!!

I have two remaining questions if you will :)
1. since you made it be a function with static variables, does it mean any edit control that is triggering this subroutine function will be working identically? if yes, nice perfect!
2. I'd like to make a dummy-proof idea where pressing the negative sign ANYWHERE INSIDE the current edit would send the minus sign to the start automatically
The only way I found is to add a checkbox that triggers another subroutine which is not the best.

How would you add the feature inside the main function?

My exemple code integrated in yours:

Code: Select all

Gui, Add, Edit, vDepenses_Montant1 gForceNumber Right
Gui, Add, Checkbox, x+2 yp+3 gRefundNegativeValue Left, Refund
Gui, Show

;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
	local
	static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []
	
	ControlGet, Pos, CurrentCol,,, ahk_id %hEdit% 	; get column number in Edit control where the caret resides
	GuiControlGet, NewNumber,, %hEdit%				; Leave Sub-command blank to retrieve control's contents
	StrReplace(NewNumber, ".",, DotCount)
	Decimals := StrLen(StrSplit(NewNumber, ".").2)
	
	BAD := (NewNumber ~= BadNeedle) 	; RegEx Match BadNeedle
        Or (DotCount > 1)			; Dots greater than one
        Or (Decimals > maxDecimals)	; Decimals greater than 2
	
	If (BAD) {
		ControlGetPos, x, y,,,, ahk_id %hEdit%
		ToolTip, %Warning%, x, y-20
		SetTimer, ForceNumber_ToolTipOff, -2000
		GuiControl,, %hEdit%, % PrevNumber[hEdit]
		SendMessage, 0xB1, % Pos-2, % Pos-2,, ahk_id %hEdit%
	}
	
	Else ; GOOD
		PrevNumber[hEdit] := NewNumber
	
	Return
	
	ForceNumber_ToolTipOff:
	ToolTip ; off
	Return
}
;-------------------------------------------------------------------------------
RefundNegativeValue() { ; insert negative sign at the start of current number
;-------------------------------------------------------------------------------
	Global
	;MsgBox checkbox
	GuiControlGet, PrevNumber,, Depenses_Montant1
	Depenses_Montant1:= PrevNumber
	;MsgBox %Depenses_Montant1%
	GuiControl,,Depenses_Montant1, -%Depenses_Montant1%
	Return
}
thanks again in advance its already way above expectations
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 06:54

1) Yes it is supposed to work with several Edit controls, but more testing might uncover bugs.

2) I tweaked your function a little (moved the -) so it does not try to put two -s. Which triggers a warning.
Effectively, we don't insert a -, but we inverse the sign of the number.

I have not yet integrated pressing the {minus} key anywhere inside.

Now we have:

Code: Select all

#NoEnv
#SingleInstance, Force
SetBatchLines, -1

    Gui, Add, Edit, gForceNumber Right
    Gui, Add, Edit, gForceNumber Right vDepenses_Montant1
    Gui, Add, Checkbox, x+2 yp+3 gRefundNegativeValue Left, Refund
    Gui, Show

Return ; end of auto-execute section

GuiClose:
ExitApp



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
	local
	static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []

	ControlGet, Pos, CurrentCol,,, ahk_id %hEdit% 	; get column number in Edit control where the caret resides
	GuiControlGet, NewNumber,, %hEdit%				; Leave Sub-command blank to retrieve control's contents
	StrReplace(NewNumber, ".",, DotCount)
	Decimals := StrLen(StrSplit(NewNumber, ".").2)

	BAD := (NewNumber ~= BadNeedle) ; NewNumber matches BadNeedle
        Or (DotCount > 1)			; Dots greater than one
        Or (Decimals > maxDecimals)	; Decimals greater than 2

	If (BAD) {
		ControlGetPos, x, y,,,, ahk_id %hEdit%
		ToolTip, %Warning%, x, y-20
		SetTimer, ForceNumber_ToolTipOff, -2000
		GuiControl,, %hEdit%, % PrevNumber[hEdit]
		SendMessage, 0xB1, % Pos-2, % Pos-2,, ahk_id %hEdit%
	}

	Else ; GOOD
		PrevNumber[hEdit] := NewNumber

	Return

	ForceNumber_ToolTipOff:
        ToolTip ; off
	Return
}



;-------------------------------------------------------------------------------
RefundNegativeValue() { ; inverse the sign of the number
;-------------------------------------------------------------------------------
	Global
	;MsgBox checkbox
	GuiControlGet, PrevNumber,, Depenses_Montant1
	Depenses_Montant1 := -PrevNumber
	;MsgBox %Depenses_Montant1%
	GuiControl,,Depenses_Montant1, %Depenses_Montant1%
	Return
}
I think you idea of allowing the {minus} key anywhere inside is great. I try that and post if semi-successful or better.
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 08:22

Awesome! :)

I've messed with it alot and been able to add two things:
1. can't have more than 1 zero after the minus sign and before the decimals
2. replace commas typed by dots just before entering the conditionnal checks

result looks like: -0.50 rather than possibly -0000.50 or -000123.50

I've also inverted the if condition thinking it would maybe save one step before the return can happen? not sure

Code: Select all

#NoEnv
#SingleInstance, Force
SetBatchLines, -1

Gui, Add, Edit, gForceNumber Right
Gui, Add, Edit, gForceNumber Right vDepenses_Montant1
Gui, Add, Checkbox, x+2 yp+3 gRefundNegativeValue Left, Refund
Gui, Show

Return ; end of auto-execute section

GuiClose:
ExitApp



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
	local
	Gui, Submit,Nohide
	static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-|^0\d|^-0\d", maxDecimals := 2, PrevNumber := []
	   ; Must be {digits}, start with ({minus} sign or not), start with (max 1 zero {0} or {-0}), cant be something like 001.50 or -005.99
	
	ControlGet, Pos, CurrentCol,,, ahk_id %hEdit% 	; get column number in Edit control where the caret resides
	GuiControlGet, NewNumber,, %hEdit%				; Leave Sub-command blank to retrieve control's contents
	
	;MsgBox %NewNumber%							; comma typed before
	NewNumber:=StrReplace(NewNumber, ",", ".")		; replace any typed commas by a dot before entering the detection
	;MsgBox %NewNumber%							; comma replaced by dot after
	
	StrReplace(NewNumber, ".",, DotCount)			; counts how many dots are trying to be typed
	Decimals := StrLen(StrSplit(NewNumber, ".").2)	; counts the decimals
	
	BAD := (NewNumber ~= BadNeedle) 				; NewNumber matches BadNeedle
        Or (DotCount > 1)						; Dots greater than one
	   Or (Decimals > maxDecimals)				; Decimals greater than 2
	
	if (Not BAD)
	{
		PrevNumber[hEdit] := NewNumber
		Return
	}
	else {
		ControlGetPos, x, y,,,, ahk_id %hEdit%
		ToolTip, %Warning%, x, y-20
		SetTimer, ForceNumber_ToolTipOff, -2000
		GuiControl,, %hEdit%, % PrevNumber[hEdit]
		SendMessage, 0xB1, % Pos-2, % Pos-2,, ahk_id %hEdit%
	}
	return
	
	ForceNumber_ToolTipOff:
	ToolTip ; off
	Return
}



;-------------------------------------------------------------------------------
RefundNegativeValue() { ; inverse the sign of the number
;-------------------------------------------------------------------------------
	Global
	;MsgBox checkbox
	GuiControlGet, PrevNumber,, Depenses_Montant1
	Depenses_Montant1 := -PrevNumber
	;MsgBox %Depenses_Montant1%
	GuiControl,,Depenses_Montant1, %Depenses_Montant1%
	Return
}
I've tried to make the auto minus sign with InStr before anything else but it doesnt work :)
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 10:07

Three lines translated. Easy to follow logic. I don't keep two versions normally, hard to maintain.

Code: Select all

    ; lets call the dirty user input not yet NewNumber
    GuiControlGet, dirtyInput,, %hEdit%

    ; the absolut value of the NewNumber we get by removing all the {minus}es
    ; at the same time, we count the {minus}es we removed
    AbsValue := StrReplace(dirtyInput, "-",, NegCount)

    ; if there was a single {minus} removed, we write down "-",
    ; otherwise (should always be 0 or 2) we write down "",
    ; then write down the AbsValue. Now we have our NewNumber
    NewNumber := (NegCount=1 ? "-" : "") AbsValue

Example with two controls:

Code: Select all

#NoEnv
#SingleInstance, Force
#Include, <ForceNumber>
SetBatchLines, -1

    Gui, Add, Edit, gForceNumber Right
    Gui, Add, Edit, gForceNumber Right
    Gui, Show

Return ; end of auto-execute section

GuiClose:
ExitApp

This is my current function all alone:
  • handles pressing {minus} ?nearly? everywhere

Code: Select all

; https://autohotkey.com/boards/viewtopic.php?p=238169#p238169
; ForceNumber.ahk



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
    local
    static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []

    ControlGet, Pos, CurrentCol,,, ahk_id %hEdit%
    GuiControlGet, dirtyInput,, %hEdit%
    AbsValue := StrReplace(dirtyInput, "-",, NegCount)
    NewNumber := (NegCount=1 ? "-" : "") AbsValue
    StrReplace(NewNumber, ".",, DotCount)
    Decimals := StrLen(StrSplit(NewNumber, ".").2)

    BAD := (NewNumber ~= BadNeedle)
        Or (DotCount > 1)
        Or (Decimals > maxDecimals)

    If (BAD) {
        ControlGetPos, x, y,,,, ahk_id %hEdit%
        ToolTip, %Warning%, x, y-20
        SetTimer, ForceNumber_ToolTipOff, -2000
        NewNumber := PrevNumber[hEdit], Pos -= 2
    }

    Else { ; GOOD
        PrevNumber[hEdit] := NewNumber
        Pos -= NegCount = 2 ? 3 : 1
    }

    GuiControl,, %hEdit%, %NewNumber%
    SendMessage, 0xB1, %Pos%, %Pos%,, ahk_id %hEdit%
    Return

    ForceNumber_ToolTipOff:
        ToolTip ; off
    Return
}
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 11:20

  • no more than one leading 0
  • needs more testing

Code: Select all

; ForceNumber.ahk



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
    local
    static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []

    ControlGet, Pos, CurrentCol,,, ahk_id %hEdit%
    GuiControlGet, dirtyInput,, %hEdit% ; <<< dirty
    AbsValue := StrReplace(dirtyInput, "-",, NegCount)
    If SubStr(AbsValue, 1, 2) = "00"
        AbsValue := SubStr(AbsValue, 2)

    ; clean
    NewNumber := (NegCount=1 ? "-" : "") AbsValue
    Decimals := StrLen(StrSplit(NewNumber, ".").2)
    StrReplace(NewNumber, ".",, DotCount)

    BAD := (NewNumber ~= BadNeedle)
        Or (Decimals > maxDecimals)
        Or (DotCount > 1)

    If (BAD) {
        ControlGetPos, x, y,,,, ahk_id %hEdit%
        ToolTip, %Warning%, x, y-20
        SetTimer, ForceNumber_ToolTipOff, -2000
        NewNumber := PrevNumber[hEdit], Pos -= 2
    }

    Else { ; GOOD
        PrevNumber[hEdit] := NewNumber
        Pos -= NegCount = 2 ? 3 : 1
    }

    GuiControl,, %hEdit%, %NewNumber%
    SendMessage, 0xB1, %Pos%, %Pos%,, ahk_id %hEdit%
    Return

    ForceNumber_ToolTipOff:
        ToolTip ; off
    Return
}
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 11:58

  • auto-converts ,

Code: Select all

; ForceNumber.ahk



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
    local
    static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []

    ControlGet, Pos, CurrentCol,,, ahk_id %hEdit%
    GuiControlGet, dirtyInput,, %hEdit% ; <<< dirty
    Converted := StrReplace(dirtyInput, ",", ".")
    AbsValue := StrReplace(Converted, "-",, NegCount)
    If SubStr(AbsValue, 1, 2) = "00"
        AbsValue := SubStr(AbsValue, 2)

    ; clean
    NewNumber := (NegCount=1 ? "-" : "") AbsValue
    Decimals := StrLen(StrSplit(NewNumber, ".").2)
    StrReplace(NewNumber, ".",, DotCount)

    BAD := (NewNumber ~= BadNeedle)
        Or (Decimals > maxDecimals)
        Or (DotCount > 1)

    If (BAD) {
        ControlGetPos, x, y,,,, ahk_id %hEdit%
        ToolTip, %Warning%, x, y-20
        SetTimer, ForceNumber_ToolTipOff, -2000
        NewNumber := PrevNumber[hEdit], Pos -= 2
    }

    Else { ; GOOD
        PrevNumber[hEdit] := NewNumber
        Pos -= (NegCount=2 ? 3 : 1)
    }

    GuiControl,, %hEdit%, %NewNumber%
    SendMessage, 0xB1, %Pos%, %Pos%,, ahk_id %hEdit%
    Return

    ForceNumber_ToolTipOff:
        ToolTip ; off
    Return
}
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 12:18

wow this is marveleous thank you so much! You got it!
It even toggle minus on/off its awesome!

The only part I was able to glitch while testing is the double leading 0 or leading 0+digits.
For example, I was able to write 011231.20 or -0994.99

So I bypassed the original RegEx line and added two additionnal condition to the RegEx.

Code: Select all

  , BadNeedle := "[^\d\.-]|^.+-|^0\d|^-0\d", maxDecimals := 2, PrevNumber := [] ;
	   ;Must be {digits}, start with ({minus} sign or not), start with (max 1 zero {0} or {-0}), cant be something like 001.50 or -005.99
It also makes it possible to bypass this part:

Code: Select all

;If SubStr(AbsValue, 1, 2) = "00" ; <<< is handled by BadNeedle's RegEx: |^0\d|^-0\d  (meaning can't start with 0 immediatly followed by another digit)
	;AbsValue := SubStr(AbsValue, 2)
	
so the resulting code with this small modification would be:

Code: Select all

; ForceNumber.ahk
;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
	local
	static Warning := "You can only enter numbers with up to 2 decimals!"
        	   , BadNeedle := "[^\d\.-]|^.+-|^0\d|^-0\d", maxDecimals := 2, PrevNumber := [] ;
	   ;Must be {digits}, start with ({minus} sign or not), start with (max 1 zero {0} or {-0}), cant be something like 001.50 or -005.99
	
	
	ControlGet, Pos, CurrentCol,,, ahk_id %hEdit%
	GuiControlGet, dirtyInput,, %hEdit% ; <<< dirty
	Converted := StrReplace(dirtyInput, ",", ".")
	AbsValue := StrReplace(Converted, "-",, NegCount)
		
	
    ; clean
	NewNumber := (NegCount=1 ? "-" : "") AbsValue
	Decimals := StrLen(StrSplit(NewNumber, ".").2)
	StrReplace(NewNumber, ".",, DotCount)
	
	BAD := (NewNumber ~= BadNeedle)
        Or (Decimals > maxDecimals)
        Or (DotCount > 1)
	
	If (BAD) {
		ControlGetPos, x, y,,,, ahk_id %hEdit%
		ToolTip, %Warning%, x, y-20
		SetTimer, ForceNumber_ToolTipOff, -2000
		NewNumber := PrevNumber[hEdit], Pos -= 2
	}
	
	Else { ; GOOD
		PrevNumber[hEdit] := NewNumber
		Pos -= NegCount = 2 ? 3 : 1
	}
	
	GuiControl,, %hEdit%, %NewNumber%
	SendMessage, 0xB1, %Pos%, %Pos%,, ahk_id %hEdit%
	Return
	
	ForceNumber_ToolTipOff:
	ToolTip ; off
	Return
}


After this, I am wondering if we MUST add Gui, Submit, no hide, to store the values of these edits in their respective variables?
Lets say these edit boxes would be the individual parts a transaction that will need to be summed-up to the grand total of the invoice. So it needs to be stored globally.
Are you able to do it without Gui, Submit?
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 12:29

I ran your modification and after typing 0, I can't type 1.
I am wondering if we MUST add Gui, Submit, no hide, to store the values of these edits in their respective variables?
Ouch, that touches on many hours spent with marginal result. I try to remember ...
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 13:02

Going back for the moment to my last version and putting two displays for the two numbers. Both numbers get displayed in the first display.
Is that somewhere close to useful to you? no GuiSubmit anywhere yet. I will try to figure out a nice way to "buddy them up" somehow, if I am on track.

Code: Select all

#NoEnv
#SingleInstance, Force
SetBatchLines, -1

    Gui, Add, Edit, gForceNumber Right
    Gui, Add, Edit, gForceNumber Right
    Gui, Add, Text, vNumberONE wp
    Gui, Add, Text, vNumberTWO wp
    Gui, Show

Return ; end of auto-execute section

GuiClose:
ExitApp



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
    local
    static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []

    ControlGet, Pos, CurrentCol,,, ahk_id %hEdit%
    GuiControlGet, dirtyInput,, %hEdit% ; <<< dirty
    Converted := StrReplace(dirtyInput, ",", ".")
    AbsValue := StrReplace(Converted, "-",, NegCount)
    If SubStr(AbsValue, 1, 2) = "00"
        AbsValue := SubStr(AbsValue, 2)

    ; clean
    NewNumber := (NegCount=1 ? "-" : "") AbsValue
    Decimals := StrLen(StrSplit(NewNumber, ".").2)
    StrReplace(NewNumber, ".",, DotCount)

    BAD := (NewNumber ~= BadNeedle)
        Or (Decimals > maxDecimals)
        Or (DotCount > 1)

    If (BAD) {
        ControlGetPos, x, y,,,, ahk_id %hEdit%
        ToolTip, %Warning%, x, y-20
        SetTimer, ForceNumber_ToolTipOff, -2000
        NewNumber := PrevNumber[hEdit], Pos -= 2
    }

    Else { ; GOOD
        PrevNumber[hEdit] := NewNumber
        Pos -= (NegCount=2 ? 3 : 1)
    }

    GuiControl,, %hEdit%, %NewNumber%
    GuiControl,, NumberONE, %NewNumber%
    SendMessage, 0xB1, %Pos%, %Pos%,, ahk_id %hEdit%

Return

    ForceNumber_ToolTipOff:
        ToolTip ; off
    Return
}

wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 13:35

It feels more intuitive to be allowed to start with 0 and still be able to type 1

Code: Select all

#NoEnv
#SingleInstance, Force
SetBatchLines, -1

    Gui, Add, Edit, gForceNumber Right
    Gui, Add, Edit, gForceNumber Right
    Gui, Add, Text, vNumberONE wp
    Gui, Add, Text, vNumberTWO wp
    Gui, Show

Return ; end of auto-execute section

GuiClose:
ExitApp



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
    local
    static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []

    ControlGet, Pos, CurrentCol,,, ahk_id %hEdit%
    GuiControlGet, dirtyInput,, %hEdit%             ; <<< dirty
    Converted := StrReplace(dirtyInput, ",", ".")
    AbsValue := StrReplace(Converted, "-",, NegCount)
    NewNumber := (NegCount=1 ? "-" : "") AbsValue   ; <<< clean
    SplitNum := StrSplit(NewNumber, ".")
    Integers := StrLen(SplitNum.1) ; # integer places
    Decimals := StrLen(SplitNum.2) ; # decimal places
    StrReplace(NewNumber, ".",, DotCount)

    ; if NewNumber has a leading 0 AND doesn't need it, => cut it off
    If SubStr(NewNumber, 1, 1) = "0" And (Integers > 1)
        NewNumber := SubStr(NewNumber, 2)

    BAD := (NewNumber ~= BadNeedle)
        Or (Decimals > maxDecimals)
        Or (DotCount > 1)

    If (BAD) { ; => complain and reject
        ControlGetPos, x, y,,,, ahk_id %hEdit%
        ToolTip, %Warning%, x, y-20
        SetTimer, ForceNumber_ToolTipOff, -2000
        NewNumber := PrevNumber[hEdit], Pos -= 2
    }

    Else { ; GOOD
        PrevNumber[hEdit] := NewNumber
        Pos -= (NegCount=2 ? 3 : 1)
    }

    GuiControl,, %hEdit%, %NewNumber%
    GuiControl,, NumberONE, %NewNumber%
    GuiControl,, NumberTwo, %MustCut%
    SendMessage, 0xB1, %Pos%, %Pos%,, ahk_id %hEdit%

Return

    ForceNumber_ToolTipOff:
        ToolTip ; off
    Return
}
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 14:46

wolf_II wrote:It feels more intuitive to be allowed to start with 0 and still be able to type 1
This is great! very nice handling of exceptions. I like how typing 0 then a number automatically interprets a typo and remove the useless leading 0

I tried different ways of keeping the unique variables:
-so far the best I found is:
1) adding vVariables to each of the EDITs that go to this gFunction
2) add setTimer before the final return
3) the new set timer uses Gui, submit
4) the GLOBAL mention must be added with the names of every variable you NEED to be global (all the rest stays local)

Code: Select all

#NoEnv
#SingleInstance, Force
SetBatchLines, -1

Gui, Add, Edit, vNumberONE gForceNumber Right
Gui, Add, Edit, vNumberTWO gForceNumber Right
; test -------------
Gui, Add, Edit, vNumberTHREE gForceNumber Right
Gui, Add, Edit, vNumberFOUR gForceNumber Right
;----------------------
Gui, Show

Return ; end of auto-execute section

GuiClose:
ExitApp



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
	Local
	static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []
	
	ControlGet, Pos, CurrentCol,,, ahk_id %hEdit%
	GuiControlGet, dirtyInput,, %hEdit%             ; <<< dirty
	Converted := StrReplace(dirtyInput, ",", ".")
	AbsValue := StrReplace(Converted, "-",, NegCount)
	NewNumber := (NegCount=1 ? "-" : "") AbsValue   ; <<< clean
	SplitNum := StrSplit(NewNumber, ".")
	Integers := StrLen(SplitNum.1) ; # integer places
	Decimals := StrLen(SplitNum.2) ; # decimal places
	StrReplace(NewNumber, ".",, DotCount)
	
    ; if NewNumber has a leading 0 AND doesn't need it, => cut it off
	If SubStr(NewNumber, 1, 1) = "0" And (Integers > 1)
		NewNumber := SubStr(NewNumber, 2)
	
	BAD := (NewNumber ~= BadNeedle)
        Or (Decimals > maxDecimals)
        Or (DotCount > 1)
	
	If (BAD) { ; => complain and reject
		ControlGetPos, x, y,,,, ahk_id %hEdit%
		ToolTip, %Warning%, x, y-20
		SetTimer, ForceNumber_ToolTipOff, -2000
		NewNumber := PrevNumber[hEdit], Pos -= 2
	}
	
	Else { ; GOOD
		PrevNumber[hEdit] := NewNumber
		Pos -= (NegCount=2 ? 3 : 1)
	}
	
	GuiControl,, %hEdit%, %NewNumber%
	;GuiControl,, NumberONE, %NewNumber%
	;GuiControl,, NumberTWO, %MustCut%
	SendMessage, 0xB1, %Pos%, %Pos%,, ahk_id %hEdit%
	
	; ----------------------------- test
	SetTimer, RefreshVariables,-500
	; ------------------------- end test
	Return
	
	
	ForceNumber_ToolTipOff:
	ToolTip ; off
	Return
	
	
	; ----------------------------- test
	RefreshVariables:
	Gui,Submit,Nohide ; <<<<------------- This is the key if not the variables dont update individually
	Global NumberONE, NumberTWO, NumberTHREE, NumberFOUR
	MsgBox, % "NumberOne = " NumberONE "`nNumberTWO = " NumberTWO "`nNumberTHREE = " NumberTHREE "`nNumberFOUR = " NumberFOUR
	return
	; ------------------------- end test
}

what do you think about that?
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 15:47

what do you think about that?
I have not looked at it yet, but I will, and come back to you.

I also made some progress, have a look if I am on track :?:
  • Bug found: can't insert 0 into -.5 to get -0.5
  • Bug found: can insert too may 0 into -.5 I lost track of which bug was exactly where
  • Changed: handling of leading 0 done earlier with AbsValue
  • Added: Hey, Buddy! (talking to buddy control)

Code: Select all

#NoEnv
#SingleInstance, Force
SetBatchLines, -1

    Gui, Add, Edit,   vNumber_001 Right gForceNumber
    Gui, Add, Text, wp vBuddy_001 Right
    Gui, Add, Edit,   vNumber_002 Right gForceNumber
    Gui, Add, Text, wp vBuddy_002 Right
    Gui, Show

Return ; end of auto-execute section

GuiClose:
GuiEscape:
ExitApp



;-------------------------------------------------------------------------------
ForceNumber(hEdit) { ; only allow numbers up to 2 decimals
;-------------------------------------------------------------------------------
    global Buddy ; auto-assume "local" for all other
    static Warning := "You can only enter numbers with up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []

    ControlGet, Pos, CurrentCol,,, ahk_id %hEdit%
    GuiControlGet, dirtyInput,, %hEdit%     ; <<< dirty
    Converted := StrReplace(dirtyInput, ",", ".")
    AbsValue := StrReplace(Converted, "-",, NegCount)

    If  SubStr(AbsValue, 1, 1) = "0"        ; if we have a leading 0
    And StrLen(AbsValue) > 1                ; AND don't need it ...
    And SubStr(AbsValue, 1, 2) != "0."      ; => cut it off
        AbsValue := SubStr(AbsValue, 2), Pos -= 1

    ; clean
    NewNumber := (NegCount=1 ? "-" : "") AbsValue
    Decimals := StrLen(StrSplit(NewNumber, ".").2)
    StrReplace(NewNumber, ".",, DotCount)

    BAD := (NewNumber ~= BadNeedle)
        Or (Decimals > maxDecimals)
        Or (DotCount > 1)

    If (BAD) { ; => complain and reject
        ControlGetPos, x, y,,,, ahk_id %hEdit%
        ToolTip, %Warning%, x, y-20
        SetTimer, ForceNumber_ToolTipOff, -2000
        NewNumber := PrevNumber[hEdit], Pos -= 2
    }

    Else { ; GOOD
        PrevNumber[hEdit] := NewNumber
        Pos -= (NegCount=2 ? 3 : 1)
    }

    GuiControl,, %hEdit%, %NewNumber%
    SendMessage, 0xB1, %Pos%, %Pos%,, ahk_id %hEdit%

    ; Hey, Buddy!
    GuiControlGet, myName, Name, %hEdit%
    ID := SubStr(myName, 7)
    GuiControl,, Buddy%ID%, %NewNumber%

Return

    ForceNumber_ToolTipOff:
        ToolTip ; off
    Return
}
Edit: global Buddy replaces local, handles everything the same as before but is less cryptic = more explicit = elegant. Thx, DRocks :thumbup:
Last edited by wolf_II on 12 Sep 2018, 16:38, edited 1 time in total.
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 16:01

You added vVar to the controls :thumbup:
I see SetTimer, use of globals and Gui,Submit. You can do that but honestly ..., maybe you can change the handling of leading 0 and all is good.

Edit:On second look, the use of globals is "automatic" in my last script, if prefer your version to do it, and will change my function. :D :thumbup:

Did you not want to avoid Gui,Submit? Has that changed, or is your code your current best approximation?
I fear, I did miss something.
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 16:34

You are extremely helpful. I'm going to test the new one right now and come back.

I don't mind HOW we get there, but all that is important is that each EDIT control that go through the gFunction will report their final content to a variable that I can use somehwere else in the script.
Thank you enourmeously. Going to test this :)
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 16:41

In case you did not notice, I edited my last script again, stealing your idea. It still functions identically. All tests should still be valid.

PS: Thanks for testing to make this possible in the first place. I'm serious. I started this how long ago?, I must look ... later
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 19:05

The hopefully final rewrite:

Code: Select all

#NoEnv
#SingleInstance, Force
SetBatchLines, -1

    Gui, Add, Edit,   vNumber_001 Right gForceNumber
    Gui, Add, Text, wp vBuddy_001 Right
    Gui, Add, Edit,   vNumber_002 Right gForceNumber
    Gui, Add, Text, wp vBuddy_002 Right
    Gui, Show

Return ; end of auto-execute section

GuiClose:
GuiEscape:
ExitApp



;-------------------------------------------------------------------------------
ForceNumber(mySelf) { ; allow only numbers up to 2 decimals
;-------------------------------------------------------------------------------
    global Buddy ; auto-assume "local" for all other
    static Warning := "Only numbers up to 2 decimals!"
        , BadNeedle := "[^\d\.-]|^.+-", maxDecimals := 2, PrevNumber := []
        
    ; start dirty
    GuiControlGet, dirtyInput,, %mySelf%
    ControlGet, Pos, CurrentCol,,, ahk_id %mySelf%
    Converted := StrReplace(dirtyInput, ",", ".")
    AbsValue := StrReplace(Converted, "-",, NegCount)

    If  SubStr(AbsValue, 1, 1) = "0"        ; if we have a leading 0
    And StrLen(AbsValue) > 1                ; AND don't need it ...
    And SubStr(AbsValue, 1, 2) != "0."      ; => cut it off
        AbsValue := SubStr(AbsValue, 2), Pos -= 1

    ; clean
    NewNumber := (NegCount=1 ? "-" : "") AbsValue
    Decimals := StrLen(StrSplit(NewNumber, ".").2)
    StrReplace(NewNumber, ".",, DotCount)

    ; with clean data we can tell which is BAD, it's one or more of these cases:
    BAD := (NewNumber ~= BadNeedle)
        Or (Decimals > maxDecimals)
        Or (DotCount > 1)

    If (BAD) { ; => complain and reject
        ControlGetPos, myX, myY,,,, ahk_id %mySelf%
        ToolTip, %Warning%, myX, myY - 20
        SetTimer, ForceNumber_ToolTipOff, -2000
        NewNumber := PrevNumber[mySelf], Pos -= 2
    }

    Else { ; GOOD, accept and remember input
        PrevNumber[mySelf] := NewNumber
        Pos -= (NegCount=2 ? 3 : 1)
    }

    ; talking to mySelf
    GuiControl,, %mySelf%, %NewNumber%
    SendMessage, 0xB1, %Pos%, %Pos%,, ahk_id %mySelf%

    ; talking to my global Buddy
    GuiControlGet, myName, Name, %mySelf%
    ID := SubStr(myName, 7)
    GuiControl,, Buddy%ID%, %NewNumber%

Return ; end of function

    ForceNumber_ToolTipOff:
        ToolTip ; off
    Return
}
wolf_II
Posts: 2688
Joined: 08 Feb 2015, 20:55

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 20:23

Check this out:
  • invisible buddies
  • Also: maybe dump all buddies :?: Not yet implmented (explemented?). Untested idea.

Code: Select all

#NoEnv
#SingleInstance, Force
SetBatchLines, -1

    ;---------------------------------------------------------------
    ; I am playing with pixels to make Buddys invisible to the user.
    ; The variables are still visble to script, just like normal.
    ; I did not test any of the variables outside of this example,
    ; and I suspect you might not need any Buddy at all! Interesting.
    ;---------------------------------------------------------------
    
    Gui, Add, Edit, vNumber_001 Right gForceNumber
    Gui, Add, Text,  vBuddy_001 Right w0 h0 ; no pixels
    Gui, Add, Edit, vNumber_002 Right yp gForceNumber
    Gui, Add, Text,  vBuddy_002 Right yp w0 h0 ; no pixels
    Gui, Show

Return ; end of auto-execute section
DRocks
Posts: 565
Joined: 08 May 2018, 10:20

Re: Gui Edit Controls: Numbers/ 2 decimal /negative value

12 Sep 2018, 22:20

Hey Wolf,

I've spent the night trying all possibilities. Got tired and now I'm not able to think clearly lol! :( haha
The function you made is quite impressive and if I use Gui, Submit, at the end even with LOCAL it will store to the vNumber_001 / 002 / 003

This is perfect.

I will show you a picture of the actual table in which I want to integrate the gForceNumber function:
Image

I don't have problems with the gForceNumber its super good!

Where I encounter problems is that if my Edits are empty and/or Disabled, they are associated a Error value.
So Its not possible to do the calculation like:

SubTotal:= Number_001 + Number_002 + Number_003 .. etc.
The result if one of these is empty will erase the SubTotal GUI display!

This is a problem for anotehr day I'm too tired and my brain will explode lol :D
Thanks for the awesome help today, I hope we continue sharing experience together its very educative and fun

Alex

EDIT: I made the OP title clearer now that it evolved

EDIT2: see next post (#21)
Last edited by DRocks on 13 Sep 2018, 01:24, edited 1 time in total.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot], Google [Bot], Spawnova and 280 guests