Jump to content
Qwerty212

Problem with doing simple operations with formated numbers inside an input

Recommended Posts

Qwerty212

Hello. I come from: https://www.autoitscript.com/forum/topic/125747-ask-format-number-as-we-type/

One user was asking if it would be possible to give format to numbers as he was typping in an input.

He wanted to add a thousands separator (I know that there are a lot of examples around the forum, but this case was very interesting because he was asking about formatting in real time as the user enters data).

I want to create a simple data collection for my job. I don't need negative numbers or decimal places. I want that the user cant input how many pieces there were at the morning, how many at the night and perform a simple subtract :(

My goal is to do something like this:

1.png

 

This is a reduced copy of my code:

#include <WindowsConstants.au3>
#include <GUIConstants.au3>

Global $mainGUI = GUICreate("", 410, 75, -1, -1)
GUISetState(@SW_SHOW, $mainGUI)
WinSetOnTop($mainGUI, "", 1)

GUICtrlCreateLabel("Quantity at morning",5,8,130,33,$ES_CENTER)
Local $firstnumber = GUICtrlCreateInput("", 5, 30, 130, 35, BitOR($ES_NUMBER, $ES_CENTER))
GUICtrlSetFont(-1, 16, 700)
GUICtrlCreateLabel("Quantity at night",140,8,130,33,$ES_CENTER)
Local $secondnumber = GUICtrlCreateInput("", 140, 30, 130, 35, BitOR($ES_NUMBER, $ES_CENTER))
GUICtrlSetFont(-1, 16, 700)
GUICtrlCreateLabel("Pieces produced today",275,8,130,33,$ES_CENTER)
Local $lastnumber = GUICtrlCreateInput("", 275, 30, 130, 35, BitOR($ES_NUMBER, $ES_CENTER))
GUICtrlSetFont(-1, 16, 700)

GUIRegisterMsg($WM_COMMAND, "_WM_COMMAND")


While 1
    $msg = GUIGetMsg()

    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit

    EndSwitch

WEnd



Func _WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)

    Local $iIDFrom = BitAND($wParam, 0xFFFF);LoWord
    Local $iCode = BitShift($wParam, 16) ;HiWord
    Local $sDecimal = ""


    If $iIDFrom = $firstnumber And $iCode = $EN_CHANGE Then
        $sInput = GUICtrlRead($firstnumber)
        Local $Output = _StringAddThousandsSep($sInput)
        GUICtrlSetData($firstnumber, $Output)
    EndIf

    If $iIDFrom = $secondnumber And $iCode = $EN_CHANGE Then
        $sInput = GUICtrlRead($secondnumber)
        Local $Output = _StringAddThousandsSep($sInput)
        GUICtrlSetData($secondnumber, $Output)
        If GUICtrlRead($firstnumber) <> "" Then
            $first = GUICtrlRead($firstnumber)
            StringRegExpReplace($first, ".", ""); I remove the thousand separator from the string
            $second = GUICtrlRead($secondnumber)
            StringRegExpReplace($second, ".", "")
            $diff = Number($second) - Number($first)
            Local $Output = _StringAddThousandsSep($diff)
            GUICtrlSetData($lastnumber, $Output)
        EndIf
    EndIf

    If $iIDFrom = $lastnumber And $iCode = $EN_CHANGE Then
        $sInput = GUICtrlRead($lastnumber)
        Local $Output = _StringAddThousandsSep($sInput)
        GUICtrlSetData($lastnumber, $Output)
    EndIf

EndFunc   ;==>_WM_COMMAND


Func _StringAddThousandsSep($s_string, $i_convert_lcid = -1, $i_current_lcid = -1)
    ; $LOCALE_USER_DEFAULT = 0x0400
    If $i_current_lcid = -1 Or $i_current_lcid = Default Then $i_current_lcid = 0x0400
    If $i_convert_lcid = -1 Or $i_convert_lcid = Default Then $i_convert_lcid = 0x0400

    ; Get lcid decimal and thousands separators
    Local $t_buff_tmp = DllStructCreate("char[4]")
    DllCall("kernel32.dll", "int", "GetLocaleInfo", "int", $i_current_lcid, _
            "int", 0x0E, "ptr", DllStructGetPtr($t_buff_tmp), "int", 4)
    If @error Then Return SetError(1, 0, "")
    Local $s_cur_dec = DllStructGetData($t_buff_tmp, 1)

    DllCall("kernel32.dll", "int", "GetLocaleInfo", "int", $i_convert_lcid, _
            "int", 0x0E, "ptr", DllStructGetPtr($t_buff_tmp), "int", 4)
    If @error Then Return SetError(1, 0, "")
    Local $s_con_dec = DllStructGetData($t_buff_tmp, 1)

    DllCall("kernel32.dll", "int", "GetLocaleInfo", "int", $i_convert_lcid, _
            "int", 0x0F, "ptr", DllStructGetPtr($t_buff_tmp), "int", 4)
    If @error Then Return SetError(1, 0, "")
    Local $s_con_tho = DllStructGetData($t_buff_tmp, 1)

    ; For later formatting
    Local $i_number = StringRegExpReplace($s_string, "(\" & $s_cur_dec & "\d+\z)|(^-|\d+)|(\D)", "$2")
    Local $i_dec = StringRegExpReplace($s_string, "(.+?\" & $s_cur_dec & ")(\d+\z)", "$2")
    If @extended = 0 Then $i_dec = ""

    Local $i_str_len = StringLen($s_string) * 4
    Local $t_numberfmt = DllStructCreate("uint;uint;uint;ptr;ptr;uint")
    Local $t_thousands = DllStructCreate("wchar[2]")
    Local $t_decimal = DllStructCreate("wchar[2]")
    Local $t_buffer = DllStructCreate("wchar[" & $i_str_len & "]")

    DllStructSetData($t_thousands, 1, $s_con_tho)
    DllStructSetData($t_decimal, 1, $s_con_dec)
    DllStructSetData($t_numberfmt, 3, 3)
    DllStructSetData($t_numberfmt, 4, DllStructGetPtr($t_decimal))
    DllStructSetData($t_numberfmt, 5, DllStructGetPtr($t_thousands))
    DllStructSetData($t_numberfmt, 6, 1)

    DllCall("kernel32.dll", "int", "GetNumberFormatW", _
            "int", $i_convert_lcid, "int", 0, _
            "wstr", $i_number, "ptr", DllStructGetPtr($t_numberfmt), _
            "ptr", DllStructGetPtr($t_buffer), "int", $i_str_len)

    If $i_dec = "" Then $s_con_dec = ""
    Return DllStructGetData($t_buffer, 1) & $s_con_dec & $i_dec
EndFunc   ;==>_StringAddThousandsSep

Thanks to the examples in the forum it format the numbers to show on screen a point (".") as thousand separator in real time as I type in the inputs, but when I'm trying to perform a simple maths operation with numbers that use the separator the results are:

2.png

psyduck.png

Any idea or hint would be pretty much aprecciatted. I have tried to change the value of $i_convert_lcid = 0x0400 to spanish values and the result wans't better.

Any help or tip would be pretty apreciatted.

 

Greets from Barcelona

Share this post


Link to post
Share on other sites
mikell

You don't need a so complicated thing...
Please try this

#include <WindowsConstants.au3>
#include <GUIConstants.au3>

Global $mainGUI = GUICreate("", 410, 75, -1, -1)
GUICtrlCreateLabel("Quantity at morning",5,8,130,33,$ES_CENTER)
Local $firstnumber = GUICtrlCreateInput("", 5, 30, 130, 35, BitOR($ES_NUMBER, $ES_CENTER))
GUICtrlSetFont(-1, 16, 700)
GUICtrlCreateLabel("Quantity at night",140,8,130,33,$ES_CENTER)
Local $secondnumber = GUICtrlCreateInput("", 140, 30, 130, 35, BitOR($ES_NUMBER, $ES_CENTER))
GUICtrlSetFont(-1, 16, 700)
GUICtrlCreateLabel("Pieces produced today",275,8,130,33,$ES_CENTER)
Local $lastnumber = GUICtrlCreateInput("", 275, 30, 130, 35, BitOR($ES_READONLY, $ES_CENTER))
GUICtrlSetFont(-1, 16, 700)
GUICtrlSetBkColor(-1, 0xffffff)
GUISetState(@SW_SHOW, $mainGUI)

GUIRegisterMsg($WM_COMMAND, "_WM_COMMAND")


While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

;=============================================

Func _WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    Local $iIDFrom = BitAND($wParam, 0xFFFF);LoWord
    Local $iCode = BitShift($wParam, 16) ;HiWord

 If $iCode = $EN_CHANGE Then
    If $iIDFrom = $firstnumber Then
        $sInput = GUICtrlRead($firstnumber)
        GUICtrlSetData($firstnumber, StringRegExpReplace(StringReplace($sInput, " ", ""), '(?<=\d)(?=(\d{3})+(?!\d))', " "))
    EndIf
    If $iIDFrom = $secondnumber Then
        $sInput = GUICtrlRead($secondnumber)
        GUICtrlSetData($secondnumber, StringRegExpReplace(StringReplace($sInput, " ", ""), '(?<=\d)(?=(\d{3})+(?!\d))', " "))
    EndIf

    $first = Number(StringReplace(GUICtrlRead($firstnumber), " ", ""))
    $second = Number(StringReplace(GUICtrlRead($secondnumber), " ", ""))
    If $second >= $first Then
        $diff = $second - $first
        GUICtrlSetData($lastnumber, StringRegExpReplace($diff, '(?<=\d)(?=(\d{3})+(?!\d))', " "))
    Else
        GUICtrlSetData($lastnumber, "0")
    EndIf
EndIf
    Return $GUI_RUNDEFMSG

EndFunc   ;==>_WM_COMMAND

 

  • Like 1

Share this post


Link to post
Share on other sites
UEZ

Please don't send me any personal message and ask for support! I will not reply!

Selection of finest graphical examples at Codepen.io

The own fart smells best!
Her 'sikim hıyar' diyene bir avuç tuz alıp koşma!
¯\_(ツ)_/¯  ٩(●̮̮̃•̃)۶ ٩(-̮̮̃-̃)۶ૐ

Share this post


Link to post
Share on other sites
Qwerty212

@Mikell, it worked like a charm. I just have to add the point to:

StringRegExpReplace(StringReplace($sInput, ".", ""), '(?<=\d)(?=(\d{3})+(?!\d))', "."))

to get what I needed.

I spent like 2 hours looking for examples, but I was more focused on the fact that there was going to be a huge difference due to the need of perform formating as I was typping :sweating:

 

Greets from Barcelona

Share this post


Link to post
Share on other sites
ViciousXUSMC

Wow that _WM_COMMAND is like another language to me.  I would love to understand more how/why it works.

Last time I looked up Hiword/LoWord I almost gave myself an aneurysm. 

Share this post


Link to post
Share on other sites
ViciousXUSMC

No, good read though. 

Helps understand a bit of what is happening but not the underlying framework, that would involve a lot more research.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×