none
COMO CAMBIAR LA COMA POR PUNTO EN LAS EXPRESIONES NUMERICAS

    Question

  • Me apareció el siguiente problema: tengo dos textbox y en cada uno introduzco valores. En uno de ellos pongo 10.5 y cuando pierde el foco hago en su LostFocus:

    me.txtprecio.text=formatnumber(me.txtprecio.text)

    cuando en el otro textbox coloco otro valor:

    me.txtganancia.text=formatnumber(me.txtganancia.text)

    en otro campo de texto hago

    Me.TxtVenta.Text = (CDbl(Me.TxtCosto.Text) + (CDbl(Me.TxtCosto.Text) * CDbl(Me.TxtGanancia.Text) / 100))

    resutla que me tira cualquier cosa!!!

    el CDbl(Me.TxtCosto.Text) me convierte el 10.5 en 1050 !!!...

    creo que es porque no me toma el punto como separador de decimales. Esto creo que en algun momento lo habia leido en alguna parte... que habia que poner la confuguracion regional... 


    Marcelo Robin
    Saturday, June 04, 2011 10:17 AM

Answers

  • "Mint Man" escribió:
     
    > Pude hacerlo caminar cambiando la configuracion regional de la PC, pero creo que no es lo mas indicado.
    Hola, Marcelo:
     
    ¡Claro que no es lo más indicado! En lugar de cambiar la configuración regional, cuestión que no se recomienda en absoluto, lo que tienes que hacer es escribir en el control TextBox el separador decimal que se corresponda con la configuración regional existente, con independencia que el usuario pulse la coma (,) o el punto decimal (.). Para ello, en el evento KeyPress del control TextBox ejecutarías lo siguiente:

    Private Sub TextBoxOnKeyPress(sender As Object, e As KeyPressEventArgs)

       
    If ((e.KeyChar = "."c) OrElse (e.KeyChar = ","c)) Then
           
    ' Obtenemos el carácter separador decimal existente
           
    ' actualmente en la configuración regional de Windows.
           
    '
           
    e.KeyChar = _
                Threading.
    Thread.CurrentThread. _
                CurrentCulture.NumberFormat.NumberDecimalSeparator.Chars(0)

       
    End If

    End Sub
     
    Y éste mismo procedimiento de evento te podría servir para todos los controles TextBox de tu formulario. Para ello, instalarías el controlador para el evento KeyPress de la siguiente manera:

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

       
    ' Instalamos el controlador para el evento KeyPress
       
    ' de todos los controles TextBox existentes en
       
    ' el formulario.
       
    '
       
    For Each ctrl As Control In Controls

           
    If (TypeOf ctrl Is TextBox) Then _
               
    AddHandler ctrl.KeyPress, AddressOf TextBoxOnKeyPress

       
    Next

    End Sub
     
    Verás como de ésta manera el resultado de la operación “no te tira cualquiera cosa”, porque en cada momento se está utilizando el separador decimal existente en la configuración regional del usuario. Pero si el usuario escribe un separador decimal distinto al existente en la configuración regional, es normal que “obtengas cualquiera cosa” menos el resultado correcto. :-)
     
    Un saludo
     

    Enrique Martínez
      [MS MVP - VB]

    Saturday, June 04, 2011 11:40 AM
    Moderator
  • "Mint Man" escribió:
     
    > si el programa lo agarrara mi jefe (65 años y usa un solo dedo para tipear todo en la PC
    > -puede estar media hora para escribir un mail-) para el los numeros son 1,230.25 con
    > esta rutina me lo convierte en 1,230,25 COSA QUE NO EXISTE!!!
     
    Me parece a mí que le vas a tener que decir a tu jefe que sólo utilice el separador decimal y que se vaya olvidando del separador de miles.
     
    > YO QUIERO QUE SI TIPEA
    > 1.223.25 QUEDE 1223.25
    > 1,223,25 QUEDE 1223.25
    > 1223.25 QUEDE 1223.25
     
    Es que para ello no te sirve lo que yo te he explicado, ni tampoco te vale cambiar la configuración regional o especificar una cultura concreta a tu aplicación. Digamos que tendrías que eliminar el carácter separador de miles y quedarte únicamente con el separador decimal, si lo hubiera, es decir, si tu jefe lo ha escrito.
     
    El siguiente procedimiento sólo admite números, el signo negativo, UN ÚNICO SEPARADOR DECIMAL y la tecla de retroceso, y no permite que se escriban más de dos números decimales:
     ''' <summary>
     ''' Evento KeyPress para los controles TextBox numéricos.
     ''' </summary>
     ''' <param name="sender">Control TextBox.</param>
     ''' <param name="e">Instancia de la clasee KeyPressEventArgs.</param>
     ''' <author>Enrique Martínez Montejo - 2011</author>
     ''' <remarks></remarks>
     Private Sub TextBoxOnKeyPressNumeric(ByVal sender As Object, ByVal e As KeyPressEventArgs)
    
      ' Referenciamos el control TextBox que ha desencadeno el evento
      '
      Dim tb As TextBox = DirectCast(sender, TextBox)
    
      ' Carácter separador decimal existente actualmente
      ' en la configuración regional de windows. 
      ' 
      Dim separadorDecimal As String = _
        Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator
    
      If ((e.KeyChar = "."c) OrElse (e.KeyChar = ","c)) Then
       ' Si en el control hay ya escrito un separador decimal, 
       ' deshechamos insertar otro separador más. 
       ' 
       If (tb.Text.IndexOf(separadorDecimal) >= 0) And Not (tb.SelectionLength <> 0) Then
        e.Handled = True
        Return
    
       Else
        If ((tb.TextLength = 0) OrElse (tb.SelectionLength > 0) OrElse _
         ((tb.TextLength = 1) And (tb.Text.Chars(0) = "-"c))) Then
         ' Si no hay ningún número, insertamos un cero
         ' antes del separador decimal.
         tb.SelectedText = "0"
        End If
    
        ' Insertamos el separador decimal. 
        '
        e.KeyChar = CChar(separadorDecimal)
        Return
       End If
      End If
    
      If (Convert.ToInt32(e.KeyChar) = 8) Then
       ' Se ha pulsado la tecla retroceso 
       Return
    
      ElseIf (e.KeyChar = "-"c) Then
       ' Únicamente si no está seleccionado el texto del control 
       If (tb.SelectionLength = 0) Then
        ' Si en el control hay ya escrito un signo menos, 
        ' deshechamos todos los que posteriormente se escriban 
        If (tb.Text.IndexOf("-"c) >= 0) Then
         e.Handled = True
         Return
        End If
    
        ' Solo permito el signo menos si aparece en primera posición 
        '
        e.Handled = (tb.SelectionStart <> 0)
       End If
    
      ElseIf (Not (Char.IsDigit(e.KeyChar))) Then
       ' No se ha pulsado un dígito. 
       e.Handled = True
       Return
    
      End If
    
      ' Si existe el separador decimal, no permitimos que
      ' se escriban más de dos números decimales.
      '
      Dim index As Integer = tb.Text.IndexOf(separadorDecimal)
    
      If (index >= 0) Then
       Dim decimales As String = tb.Text.Substring(index + 1)
       e.Handled = (decimales.Length = 2)
      End If
    
      ' Si el texto del control actualmente está seleccionado, 
      ' permitimos que se pueda reemplazar por el carácter tecleado.
      '
      If (tb.SelectionLength > 0) Then e.Handled = False
    
     End Sub
    

    Ahora, para no tener que insertar el código fuente en todos los eventos KeyPress de los distintos controles TextBox numéricos, en el evento Load del formulario instalarías el controlador para el evento KeyPress de la siguiente manera:

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load

        AddHandler TextBox1.KeyPress, AddressOf TextBoxOnKeyPressNumeric

    End Sub

    Y cuando el control TextBox pierda el foco, ENTONCES ES CUANDO TIENES QUE FORMATEAR EL NÚMERO, para que tu jefe lo vea como él desea verlo:

        Private Sub TextBox1_LostFocus(sender As Object, e As EventArgs) Handles TextBox1.LostFocus
     
            Dim d As Decimal
     
            Dim bln As Boolean = Decimal.TryParse(TextBox1.Text, d)
     
            If (bln) Then
                TextBox1.Text = String.Format("{0:N2}", d)
     
            Else
                TextBox1.Clear()
     
            End If
     
        End Sub

    Enrique Martínez
      [MS MVP - VB]

    Saturday, June 04, 2011 1:02 PM
    Moderator

All replies

  • Pude hacerlo caminar cambiando la configuracion regional de la PC, pero creo que no es lo mas indicado. Creo que por código podría evitarme tener que testear esa cuestión manualmente... no es asi?

    Saludos


    Marcelo Robin
    Saturday, June 04, 2011 10:24 AM
  • Gracias muchachos... ya lo solucione poniendo en el modulo Main de la aplicacion:

     

    Dim culture As New System.Globalization.CultureInfo("es-ES")

     

    culture.NumberFormat.CurrencyDecimalSeparator = "."

     

    culture.NumberFormat.CurrencyGroupSeparator = ","

    culture.NumberFormat.NumberDecimalSeparator = "."

    System.Threading.Thread.CurrentThread.CurrentCulture = culture

    Y ASUNTO SOLUCIONADO...

     


    Marcelo Robin
    Saturday, June 04, 2011 11:31 AM
  • "Mint Man" escribió:
     
    > Pude hacerlo caminar cambiando la configuracion regional de la PC, pero creo que no es lo mas indicado.
    Hola, Marcelo:
     
    ¡Claro que no es lo más indicado! En lugar de cambiar la configuración regional, cuestión que no se recomienda en absoluto, lo que tienes que hacer es escribir en el control TextBox el separador decimal que se corresponda con la configuración regional existente, con independencia que el usuario pulse la coma (,) o el punto decimal (.). Para ello, en el evento KeyPress del control TextBox ejecutarías lo siguiente:

    Private Sub TextBoxOnKeyPress(sender As Object, e As KeyPressEventArgs)

       
    If ((e.KeyChar = "."c) OrElse (e.KeyChar = ","c)) Then
           
    ' Obtenemos el carácter separador decimal existente
           
    ' actualmente en la configuración regional de Windows.
           
    '
           
    e.KeyChar = _
                Threading.
    Thread.CurrentThread. _
                CurrentCulture.NumberFormat.NumberDecimalSeparator.Chars(0)

       
    End If

    End Sub
     
    Y éste mismo procedimiento de evento te podría servir para todos los controles TextBox de tu formulario. Para ello, instalarías el controlador para el evento KeyPress de la siguiente manera:

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

       
    ' Instalamos el controlador para el evento KeyPress
       
    ' de todos los controles TextBox existentes en
       
    ' el formulario.
       
    '
       
    For Each ctrl As Control In Controls

           
    If (TypeOf ctrl Is TextBox) Then _
               
    AddHandler ctrl.KeyPress, AddressOf TextBoxOnKeyPress

       
    Next

    End Sub
     
    Verás como de ésta manera el resultado de la operación “no te tira cualquiera cosa”, porque en cada momento se está utilizando el separador decimal existente en la configuración regional del usuario. Pero si el usuario escribe un separador decimal distinto al existente en la configuración regional, es normal que “obtengas cualquiera cosa” menos el resultado correcto. :-)
     
    Un saludo
     

    Enrique Martínez
      [MS MVP - VB]

    Saturday, June 04, 2011 11:40 AM
    Moderator
  • Enrique, es muy interesante la opción que me presentas. La subrutina Private Sub TextBoxOnKeyPress(sender As Object, e As KeyPressEventArgs) podría ponerla en un módulo general donde defino variables pero como PUBLIC ? 

    Y cada 

      For Each ctrl As Control In Controls

            
    If (TypeOf ctrl Is TextBoxThen _
                
    AddHandler ctrl.KeyPress, AddressOf TextBoxOnKeyPress

        
    Next

    tendría que ponerlo en cada formulario... que maneje textboxes con numeros... 

    Saludos


    Marcelo Robin
    Saturday, June 04, 2011 11:46 AM
  • "Mint Man" escribió:
     
    > Gracias muchachos... ya lo solucione poniendo en el modulo Main de la aplicacion:
    >
    > Dim culture As New System.Globalization.CultureInfo("es-ES")
    >
    > culture.NumberFormat.CurrencyDecimalSeparator = "."
    > culture.NumberFormat.CurrencyGroupSeparator = ","
    > culture.NumberFormat.NumberDecimalSeparator = "."
    > System.Threading.Thread.CurrentThread.CurrentCulture = culture
    >
    > Y ASUNTO SOLUCIONADO...
     
    ¡Que crees tú que el asunto está solucionado! Ahora cuando el usuario escriba la coma como separador decimal, vas a obtener un resultado que no es correcto, es decir, lo contrario que te estaba ocurriendo anteriormente. :-)
     
    A mi entender, NO SE PUEDE ESPECIFICAR UNA CULTURA CONCRETA A UNA APLICACIÓN. Nuestra aplicación se tiene que adaptar en todo momento a la cultura existente en la configuración regional del usuario. Si el usuario tiene una configuración regional de español, le gustará utilizar la coma para separar los decimales. Y si tiene una cultura de inglés, le gustará utilizar el punto decimal. La solución, la que te he indicado en mi anterior respuesta.
     
     
     
     
     
     

    Enrique Martínez
      [MS MVP - VB]

    Saturday, June 04, 2011 11:46 AM
    Moderator
  • "Mint Man" preguntó:
     
    > La subrutina Private Sub TextBoxOnKeyPress(sender As Object, e As KeyPressEventArgs) podría
    > ponerla en un módulo general donde defino variables pero como PUBLIC ?
     
    Sí.
     
    > Y cada
    >
    >  For Each ctrl As Control In Controls
    >
    >        If (TypeOf ctrl Is TextBox) Then _
    >            AddHandler ctrl.KeyPress, AddressOf TextBoxOnKeyPress
    >
    >    Next
    >
    > tendría que ponerlo en cada formulario... que maneje textboxes con numeros...
     
    En todos aquellos controles TextBox donde quieras hacer cálculos donde intervenga el carácter separador decimal. He supuesto que todos los controles TextBox de tu formulario van a efectuar cálculos aritméticos, de ahí que se recorra la colección de controles del formulario para instalar el controlador de evento KeyPress a todos los controles TextBox existentes.
     
    Si solamente son dos controles TextBox, podrías hacerlo de la siguiente manera:
     
        AddHandler TextBox1.KeyPress, AddressOf TextBoxOnKeyPress
        AddHandler TextBox2.KeyPress, AddressOf TextBoxOnKeyPress
     
     
     
     
     

    Enrique Martínez
      [MS MVP - VB]

    Saturday, June 04, 2011 11:51 AM
    Moderator
  • Aja, ya entendi...

    Private Sub TextBoxOnKeyPress(sender As Object, e As KeyPressEventArgs)

        
    If ((e.KeyChar = "."cOrElse (e.KeyChar = ","c)) Then
            
    ' Obtenemos el carácter separador decimal existente
            
    ' actualmente en la configuración regional de Windows.
            

            
    e.KeyChar = _
                Threading.
    Thread.CurrentThread. _
                CurrentCulture.NumberFormat.NumberDecimalSeparator.Chars(0)

        
    End If

    End Sub

     

    Lo tengo que poner en cada keypress de cada textbox que esta en el formulario y maneja numeros decimales... 

    Que pasa si el usuario quiere poner 1500.35 y tipea: 1.500.35 ?


    Marcelo Robin
    Saturday, June 04, 2011 11:54 AM
  • "Mint Man" preguntó:
     
    > Que pasa si el usuario quiere poner 1500.35 y tipea: 1.500.35 ?
     
    Que tal y como está el ejemplo que te he indicado, tendría DOS SEPARADORES DECIMALES.
    Pero ello es una situación que tu aplicación no debería de permitir. Es igual que si
    me preguntas qué sucedería si el usuario escribe 1.500,35, o introduce un carácter
    alfabético: 1.500A.
     
    Estas son cuestiones que no deberías de permitir. Si el usuario ha escrito un
    separador decimal, no debes dejar que escriba un segundo carácter decimal si tu
    intención es efectuar cálculos aritméticos con el valor escrito en el control TextBox.
     
     
     
     
     
     
     

    Enrique Martínez
      [MS MVP - VB]


    Saturday, June 04, 2011 12:07 PM
    Moderator
  • Estoy teniendo problemas con este código.

    Por ejemplo si tipeo: 12.30 el punto me lo reemplaza por una coma y en el textbox queda 12,30 NINGUN PROBLEMA

    si tipeo 12,30 queda tal cual...

    el problema existe con los millares:

    si tipeo 1230.30 el punto me lo reemplaza por una coma y en el textbox queda 1230,30 NINGUN PROBLEMA.

    En cambio... si el programa lo agarrara mi jefe (65 años y usa un solo dedo para tipear todo en la PC -puede estar media hora para escribir un mail-) para el los numeros son 1,230.25 con esta rutina me lo convierte en 1,230,25 COSA QUE NO EXISTE!!!

    PERO SI ESCRIBIERA: 1.230,25 TAMBIEN ME DEJARIA 1,230,25 IGUAL QUE EL CASO ANTERIOR!!!

    YO QUIERO QUE SI TIPEA

    1.223.25 QUEDE 1223.25

    1,223,25 QUEDE 1223.25

    1223.25 QUEDE 1223.25


    Marcelo Robin
    Saturday, June 04, 2011 12:18 PM
  • "Mint Man" escribió:
     
    > si el programa lo agarrara mi jefe (65 años y usa un solo dedo para tipear todo en la PC
    > -puede estar media hora para escribir un mail-) para el los numeros son 1,230.25 con
    > esta rutina me lo convierte en 1,230,25 COSA QUE NO EXISTE!!!
     
    Me parece a mí que le vas a tener que decir a tu jefe que sólo utilice el separador decimal y que se vaya olvidando del separador de miles.
     
    > YO QUIERO QUE SI TIPEA
    > 1.223.25 QUEDE 1223.25
    > 1,223,25 QUEDE 1223.25
    > 1223.25 QUEDE 1223.25
     
    Es que para ello no te sirve lo que yo te he explicado, ni tampoco te vale cambiar la configuración regional o especificar una cultura concreta a tu aplicación. Digamos que tendrías que eliminar el carácter separador de miles y quedarte únicamente con el separador decimal, si lo hubiera, es decir, si tu jefe lo ha escrito.
     
    El siguiente procedimiento sólo admite números, el signo negativo, UN ÚNICO SEPARADOR DECIMAL y la tecla de retroceso, y no permite que se escriban más de dos números decimales:
     ''' <summary>
     ''' Evento KeyPress para los controles TextBox numéricos.
     ''' </summary>
     ''' <param name="sender">Control TextBox.</param>
     ''' <param name="e">Instancia de la clasee KeyPressEventArgs.</param>
     ''' <author>Enrique Martínez Montejo - 2011</author>
     ''' <remarks></remarks>
     Private Sub TextBoxOnKeyPressNumeric(ByVal sender As Object, ByVal e As KeyPressEventArgs)
    
      ' Referenciamos el control TextBox que ha desencadeno el evento
      '
      Dim tb As TextBox = DirectCast(sender, TextBox)
    
      ' Carácter separador decimal existente actualmente
      ' en la configuración regional de windows. 
      ' 
      Dim separadorDecimal As String = _
        Threading.Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator
    
      If ((e.KeyChar = "."c) OrElse (e.KeyChar = ","c)) Then
       ' Si en el control hay ya escrito un separador decimal, 
       ' deshechamos insertar otro separador más. 
       ' 
       If (tb.Text.IndexOf(separadorDecimal) >= 0) And Not (tb.SelectionLength <> 0) Then
        e.Handled = True
        Return
    
       Else
        If ((tb.TextLength = 0) OrElse (tb.SelectionLength > 0) OrElse _
         ((tb.TextLength = 1) And (tb.Text.Chars(0) = "-"c))) Then
         ' Si no hay ningún número, insertamos un cero
         ' antes del separador decimal.
         tb.SelectedText = "0"
        End If
    
        ' Insertamos el separador decimal. 
        '
        e.KeyChar = CChar(separadorDecimal)
        Return
       End If
      End If
    
      If (Convert.ToInt32(e.KeyChar) = 8) Then
       ' Se ha pulsado la tecla retroceso 
       Return
    
      ElseIf (e.KeyChar = "-"c) Then
       ' Únicamente si no está seleccionado el texto del control 
       If (tb.SelectionLength = 0) Then
        ' Si en el control hay ya escrito un signo menos, 
        ' deshechamos todos los que posteriormente se escriban 
        If (tb.Text.IndexOf("-"c) >= 0) Then
         e.Handled = True
         Return
        End If
    
        ' Solo permito el signo menos si aparece en primera posición 
        '
        e.Handled = (tb.SelectionStart <> 0)
       End If
    
      ElseIf (Not (Char.IsDigit(e.KeyChar))) Then
       ' No se ha pulsado un dígito. 
       e.Handled = True
       Return
    
      End If
    
      ' Si existe el separador decimal, no permitimos que
      ' se escriban más de dos números decimales.
      '
      Dim index As Integer = tb.Text.IndexOf(separadorDecimal)
    
      If (index >= 0) Then
       Dim decimales As String = tb.Text.Substring(index + 1)
       e.Handled = (decimales.Length = 2)
      End If
    
      ' Si el texto del control actualmente está seleccionado, 
      ' permitimos que se pueda reemplazar por el carácter tecleado.
      '
      If (tb.SelectionLength > 0) Then e.Handled = False
    
     End Sub
    

    Ahora, para no tener que insertar el código fuente en todos los eventos KeyPress de los distintos controles TextBox numéricos, en el evento Load del formulario instalarías el controlador para el evento KeyPress de la siguiente manera:

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load

        AddHandler TextBox1.KeyPress, AddressOf TextBoxOnKeyPressNumeric

    End Sub

    Y cuando el control TextBox pierda el foco, ENTONCES ES CUANDO TIENES QUE FORMATEAR EL NÚMERO, para que tu jefe lo vea como él desea verlo:

        Private Sub TextBox1_LostFocus(sender As Object, e As EventArgs) Handles TextBox1.LostFocus
     
            Dim d As Decimal
     
            Dim bln As Boolean = Decimal.TryParse(TextBox1.Text, d)
     
            If (bln) Then
                TextBox1.Text = String.Format("{0:N2}", d)
     
            Else
                TextBox1.Clear()
     
            End If
     
        End Sub

    Enrique Martínez
      [MS MVP - VB]

    Saturday, June 04, 2011 1:02 PM
    Moderator
  • Esta sí me gusto... acá no toco la configuración regional aunque el programa lo estén ejecutando en Sri Lanka... 

    Fantástico... 

    Muchisimas Gracias !!!

    PD: creo que mi jefe no tiene solución alguna :-P


    Marcelo Robin
    Saturday, June 04, 2011 1:28 PM