PlanetSquires Forums

Support Forums => Other Software and Code => Topic started by: Jean-pierre Leroy on January 21, 2010, 06:17:54 PM

Title: FireTextBox when used with different regional settings (decimal separator)
Post by: Jean-pierre Leroy on January 21, 2010, 06:17:54 PM
Paul,

1. Minor Point: When I insert a new FireTextBox control, the font is always "Tahoma 8" and not the default font specified in "Tools->Environment Options->Visual Designer->Fonts->Default font for new control; could be easy to fix I presume.

2. Nice to have: On my PC, I use the comma (,) as the decimal separator; when I use a FireTextBox control with a Numeric mask style, I can't use the decimal point (.) from the numeric keypad as a decimal separator, I've to use the comma (,) on the normal keyboard; in Excel by example, I can use the decimal point from the numeric keypad as a decimal separator and the decimal point is automatically transformed in a coma (,) in the excel sheet; I don't know if it could be possible to implement such a feature with the FireTextBox.

3. Important point to be aware: I started to replace some TextBoxes by FireTextBoxes on some of my project; theses boxes were used to fill in Numeric value.

To extract the value from TextBox, I usually used this code:


Local lValue As Double
lValue = Val(FF_TextBox_GetText(HWND_FORM1_TEXT1))


So at first I used the same code with FireTextBoxe:


Local lValue As Double
lValue = Val(FF_TextBox_GetText(HWND_FORM1_FIRETEXTBOX1))


But the returned value was not exactly the same; here are the results when the user fill the value 12345.67

Quote
lValue with TextBox=12345.67
lValue with FireTextBox=12345

So I understand very quickly that the val() function doesn't evaluate correctly the decimal value due to the comma (,) instead of a decimal point (.); so to make it work I add a replace command in my code:


Local lValue As Double
Local lStringFireTextBox As String
lStringFireTextBox = FF_TextBox_GetText(HWND_FORM1_FIRETEXTBOX1)
Replace "," With "." In lStringFireTextBox
lValue = Val(lStringFireTextBox)


Now I get the right value, but then I have a question:

If my program is used on another computer with other option for the decimal point, how can I ensure "portability" of my software on this new PC ?

Here is my question: can you provide some standard function that extract the numeric value from the FireTextBox control that take into account dynamically the decimal separator and the group separator used by the computer; I was thinking of functions like :

FF_FireTextBox_GetSingleNumeric()
FF_FireTextBox_GetDoubleNumeric()
FF_FireTextBox_GetExtendedNumeric()
...

Does it make sense ?

Thanks,
Jean-Pierre
Title: Re: FireTextBox when used with different regional settings (decimal separator)
Post by: Paul Squires on January 21, 2010, 08:55:42 PM
Thanks Jean-Pierre, I'll have to think about this a bit more. Regional settings for the various
Quote from: Jean-Pierre Leroy on January 21, 2010, 06:17:54 PM
Paul,

1. Minor Point: When I insert a new FireTextBox control, the font is always "Tahoma 8" and not the default font specified in "Tools->Environment Options->Visual Designer->Fonts->Default font for new control; could be easy to fix I presume.

That setting seems to be working okay for me. I'll check again tomorrow, but when I changed the default control font then all new FireTextBoxes and FireLink's that I created used that new default font.

Quote
2. Nice to have: On my PC, I use the comma (,) as the decimal separator; when I use a FireTextBox control with a Numeric mask style, I can't use the decimal point (.) from the numeric keypad as a decimal separator, I've to use the comma (,) on the normal keyboard; in Excel by example, I can use the decimal point from the numeric keypad as a decimal separator and the decimal point is automatically transformed in a coma (,) in the excel sheet; I don't know if it could be possible to implement such a feature with the FireTextBox.

That's pretty interesting. I assume that Excel itself must do some type remapping or internal conversions of all periods to commas. Very interesting. I could see such a feature being built into the FireTextBox code.

Quote
But the returned value was not exactly the same; here are the results when the user fill the value 12345.67

Quote
lValue with TextBox=12345.67
lValue with FireTextBox=12345

It returns perfectly for me. I mean all you are doing is converting "12345.67". I don't see any commas in the code you are using?

Quote
So I understand very quickly that the val() function doesn't evaluate correctly the decimal value due to the comma (,) instead of a decimal point (.); so to make it work I add a replace command in my code:

Yes, you're right. PB's help for VAL specifically says: "The string argument should not contain any commas, as VAL terminates processing if a comma is encountered."


Quote
If my program is used on another computer with other option for the decimal point, how can I ensure "portability" of my software on this new PC ?

I think that your application would have to test for the Local. Check out the code that I use in the FireTextBox.inc source code for determining the default symbols:

Quote
Function FF_FilterNumeric_GetSymbols( ByVal ed         As FIRETEXTBOX_DATA Ptr, _
                                      ByRef sNumbers   As String, _
                                      ByRef sPrefix    As String, _
                                      ByRef sThousands As String, _
                                      ByRef sDecimal   As String, _
                                      ByRef sNegative  As String _
                                      ) As Long
                                     
   Local zBuffer As Asciiz * 10
   
   sNumbers  = "0123456789"
   sNegative = "-"

   If @ed.fCurrencyPrefix Then
      sPrefix = "$"
      If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SCURRENCY, zBuffer, SizeOf(zBuffer)) Then
         sPrefix = zBuffer
      End If
   End If

   If @ed.fDecimalPoint Then
      sDecimal = "."
      If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONDECIMALSEP, zBuffer, SizeOf(zBuffer)) Then
         sDecimal = zBuffer
      End If
   End If

   If @ed.fGroupSeparator Then
      sThousands = ","
      If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONTHOUSANDSEP, zBuffer, SizeOf(zBuffer)) Then
         sThousands = zBuffer
      End If   
   End If

End Function

Quote
Here is my question: can you provide some standard function that extract the numeric value from the FireTextBox control that take into account dynamically the decimal separator and the group separator used by the computer; I was thinking of functions like :

FF_FireTextBox_GetSingleNumeric()
FF_FireTextBox_GetDoubleNumeric()
FF_FireTextBox_GetExtendedNumeric()

Possibly. I guess it could become a part of the basic source code of the FireTextBox.inc itself. I'll see what I can do over the next few days.

Title: Re: FireTextBox when used with different regional settings (decimal separator)
Post by: Wilko Verweij on January 22, 2010, 04:11:48 AM
I will have to check what  the FireTextBox can mean for me. I had the same problem as Jean-Pierre (not typically FF, nor typically PowerBasic) and always checked for the settings of the user:
Function GetDecPointChar$()

  Dim cchData As Long
  Dim LCType As Long
  Dim Locale As Long
  Dim lpLCData As Asciiz*51
  Dim Tmp As Long

  Locale = GetUserDefaultLCID
  LCType = %LOCALE_SDECIMAL
  lpLCData = Space$(50)
  cchData = Len(lpLCData)

  Tmp = GetLocaleInfo(Locale, LCType, lpLCData, cchData)
  GetDecPointChar$ = Left$(lpLCData, Tmp- 1)

End Function   

That retrieved the decimal point character for the user (not PC-dependent but user-dependent) but may be the FireTextBox is better.

I added functions like SafeVal where any comma's were transformed into "." before applying the VAL-statement, similar to your solution.



Wilko
Title: Re: FireTextBox when used with different regional settings (decimal separator)
Post by: Jean-pierre Leroy on January 22, 2010, 09:59:56 AM
Paul,

I have written 3 functions FF_FireTextBox_GetSingle(), FF_FireTextBox_GetDouble and FF_FireTextBox_GetExtended; these functions can retrieve the numeric value of a FireTextBox control (with a numeric mask style) regardless of the regional settings of the PC (decimal separator and thousands separator).

Perhaps there is a more elegant way to write these functions; at least for the time being it solved my issue.

I would like to warn other FireFly users not to use directly the VAL() function on the result of the FF_TextBox_GetText() in order to evaluate the numeric value of a FireTextBox control (with a numeric mask style) like below :


Local lValue As Double
lValue = Val(FF_TextBox_GetText(HWND_FORM1_FIRETEXTBOX1))


Due to the fact that the FireTextBox control uses the regional settings to display the decimal separator and the thousands separator (which is indeed a good idea) a direct evaluation could lead to different results depending on the regional settings of the PC (decimal separator and thousands separator).

Hope that helps.
Jean-Pierre


Function FF_FireTextBox_GetSingle(ByVal hWndControl As Dword) As Single

    ' to evaluate the FireTextBox
    Local lFireTextBox As String

    ' to retrieve locale windows settings
    Local lBuffer    As Asciiz * 10
    Local lDecimal   As String
    Local lThousands As String
   
    ' Do a check to ensure that this is actually a window handle
    If IsWindow(hWndControl) Then   
                 
        ' retrieve the "Decimal Separator"
        If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONDECIMALSEP, lBuffer, SizeOf(lBuffer)) Then
            lDecimal = lBuffer                           
        End If
       
        ' retrieve the "Thousands Separator"
        If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONTHOUSANDSEP, lBuffer, SizeOf(lBuffer)) Then
            lThousands = lBuffer               
        End If
       
        ' retrieve the string value from the FireTextBox control
        lFireTextBox = FF_TextBox_GetText(hWndControl)
       
        ' replace the "Decimal Separator" by a point (.) if necessary
        If lDecimal <> "." Then Replace lDecimal With "." In lFireTextBox
       
        ' remove the "Thousands Separator"
        lFireTextBox = Remove$(lFireTextBox, lThousands) 
       
        ' return the numeric value
        Function = Val(lFireTextBox)   

    End If                 
       
End Function   



Function FF_FireTextBox_GetDouble(ByVal hWndControl As Dword) As Double

    ' to evaluate the FireTextBox
    Local lFireTextBox As String

    ' to retrieve locale windows settings
    Local lBuffer    As Asciiz * 10
    Local lDecimal   As String
    Local lThousands As String
   
    ' Do a check to ensure that this is actually a window handle
    If IsWindow(hWndControl) Then   
                 
        ' retrieve the "Decimal Separator"
        If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONDECIMALSEP, lBuffer, SizeOf(lBuffer)) Then
            lDecimal = lBuffer               
        End If
       
        ' retrieve the "Thousands Separator"
        If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONTHOUSANDSEP, lBuffer, SizeOf(lBuffer)) Then
            lThousands = lBuffer               
        End If
       
        ' retrieve the string value from the FireTextBox control
        lFireTextBox = FF_TextBox_GetText(hWndControl)
       
        ' replace the "Decimal Separator" by a point (.) if necessary
        If lDecimal <> "." Then Replace lDecimal With "." In lFireTextBox
       
        ' remove the "Thousands Separator"
        lFireTextBox = Remove$(lFireTextBox, lThousands) 
       
        ' return the numeric value
        Function = Val(lFireTextBox)   

    End If                 
       
End Function   



Function FF_FireTextBox_GetExtended(ByVal hWndControl As Dword) As Extended

    ' to evaluate the FireTextBox
    Local lFireTextBox As String

    ' to retrieve locale windows settings
    Local lBuffer    As Asciiz * 10
    Local lDecimal   As String
    Local lThousands As String
   
    ' Do a check to ensure that this is actually a window handle
    If IsWindow(hWndControl) Then   
                 
        ' retrieve the "Decimal Separator"
        If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONDECIMALSEP, lBuffer, SizeOf(lBuffer)) Then
            lDecimal = lBuffer               
        End If
       
        ' retrieve the "Thousands Separator"
        If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONTHOUSANDSEP, lBuffer, SizeOf(lBuffer)) Then
            lThousands = lBuffer               
        End If
       
        ' retrieve the string value from the FireTextBox control
        lFireTextBox = FF_TextBox_GetText(hWndControl)
       
        ' replace the "Decimal Separator" by a point (.) if necessary
        If lDecimal <> "." Then Replace lDecimal With "." In lFireTextBox
       
        ' remove the "Thousands Separator"
        lFireTextBox = Remove$(lFireTextBox, lThousands) 
       
        ' return the numeric value
        Function = Val(lFireTextBox)   

    End If                 
       
End Function   
Title: Re: FireTextBox when used with different regional settings (decimal separator)
Post by: Paul Squires on January 22, 2010, 11:00:24 AM
Thanks Jean-Pierre,

That is certainly a big help and has saved me a bit of work ;)

I am curious as to why 3 separate functions are necessary. Why not just use one function to return the value as a Double and allow PB to automatically cast the value to fit the variable it is being assigned to?


Local myValue As Currency
myValue = FF_FireTextBox_GetDouble( HWND_FORM1_FIRETEXTBOX1 )


I would think that Double would have more than digit holders that someone entering or displaying the value in the textbox would never exceed it.
Title: Re: FireTextBox when used with different regional settings (decimal separator)
Post by: Jean-pierre Leroy on January 22, 2010, 01:27:36 PM
Paul,

You're right it is useless to have 3 separate functions; so my suggestions are:

1. To use one function called FF_FireTextBox_GetNumeric() in order to mimic the "Mask style" mentioned in the FireTextBox control.
2. To return the value as Extended as it seems that extended-precision are the basis of computation in PowerBASIC; from the doc:

QuoteExtended-precision  numbers are the basis of computation in PowerBASIC.  The type-specifier character for an Extended-precision floating-point is: ##.  In PowerBASIC, all floating point calculations are performed in extended precision for maximum accuracy.  Extended-precision has also been provided as a declarable variable type, so you can take advantage of its extra exponent range and precision.

Here is the latest version of the proposed FF_FireTextBox_GetNumeric() function:


Function FF_FireTextBox_GetNumeric(ByVal hWndControl As Dword) As Extended

    ' to evaluate the FireTextBox
    Local lFireTextBox As String

    ' to retrieve locale windows settings
    Local lBuffer    As Asciiz * 10
    Local lDecimal   As String
    Local lThousands As String
   
    ' Do a check to ensure that this is actually a window handle
    If IsWindow(hWndControl) Then   
                 
        ' retrieve the "Decimal Separator"
        If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONDECIMALSEP, lBuffer, SizeOf(lBuffer)) Then
            lDecimal = lBuffer               
        End If
       
        ' retrieve the "Thousands Separator"
        If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONTHOUSANDSEP, lBuffer, SizeOf(lBuffer)) Then
            lThousands = lBuffer               
        End If
       
        ' retrieve the string value from the FireTextBox control
        lFireTextBox = FF_TextBox_GetText(hWndControl)
       
        ' replace the "Decimal Separator" by a point (.) if necessary
        If lDecimal <> "." Then Replace lDecimal With "." In lFireTextBox
       
        ' remove the "Thousands Separator"
        lFireTextBox = Remove$(lFireTextBox, lThousands) 
       
        ' return the numeric value
        Function = Val(lFireTextBox)   

    End If                 
       
End Function


Tell me if it makes sense,

Regards,
Jean-Pierre
Title: Re: FireTextBox when used with different regional settings (decimal separator)
Post by: Paul Squires on January 22, 2010, 03:07:38 PM
Thanks Jean-Pierre, I have added your function to the standard list of FF Functions that ship with FF3.
Title: Re: FireTextBox when used with different regional settings (decimal separator)
Post by: Jean-pierre Leroy on February 01, 2010, 06:58:08 PM
Paul,

Thank you for added the function FF_FireTextBox_GetNumeric() to the standard list of FF Functions that ship with FF3.

Today I had a similar issue when I tried to refresh back a FireTextBox control with the result of a computation; if I update directly the FireTextBox control with the function FF_TextBox_SetText the decimal separator is not displayed.

So I created a new sub that I called FF_FireTextBox_SetNumeric() to set a numeric value in a FireTextBox control.

Here is the source code of the proposed FF_FireTextBox_SetNumeric() function:


Sub FF_FireTextBox_SetNumeric(ByVal hWndControl As Dword, ByVal pNumeric As Extended)

    ' the string that will contain the numeric value
    Local lFireTextBox As String

    ' to retrieve locale windows settings
    Local lBuffer    As Asciiz * 10
    Local lDecimal   As String
   
    ' Do a check to ensure that this is actually a window handle
    If IsWindow(hWndControl) Then   
                 
        ' retrieve the "Decimal Separator"
        If GetLocaleInfo(%LOCALE_USER_DEFAULT, %LOCALE_SMONDECIMALSEP, lBuffer, SizeOf(lBuffer)) Then
            lDecimal = lBuffer               
        End If
       
        ' convert the numeric value in string
        lFireTextBox = LTrim$(Str$(pNumeric))
               
        ' replace the "." by the "Decimal Separator" if necessary
        If lDecimal <> "." Then Replace "." With lDecimal In lFireTextBox
               
        ' set the numeric value in the FireTextBox control
        FF_TextBox_SetText(hWndControl, lFireTextBox)

    End If                 
       
End Sub


Everything works fine except a small issue; when I update the FireTextBox control the number of decimal places is not respected; on the enclosed example we can see 3 decimal places even if the control is defined with 2 decimal places.

Regards,
Jean-Pierre
Title: Re: FireTextBox when used with different regional settings (decimal separator)
Post by: Paul Squires on February 01, 2010, 08:17:54 PM
This is corrected now. The control would not format the number when it was initially set in the control. It would only format the trailing zeros when the focus left the control (ie. on WM_KILLFOCUS).