none
Multiplicar dos textbox con decimales

    Pregunta

  • Hola, recurro a vostros por que no encuentro la forma de multiplicar dos textbox y que me saquen los decimales...
    Tengo un campo en SQL que es Float y el resultado de la multiplicación debe ir ahí.

    He probado varias cosas y no funciona, ahora lo tengo así:

                    Dim total As Decimal = CDec(TxtCosto.Text) * CDec(TxtCantidad.Text)
                    total = Math.Round(total, 3)
    Y nada... si multiplico 50*11.75 me da 58750
    No entiendo por que no pone  587.50...DIOSSS que desesperación.

    sábado, 10 de septiembre de 2016 11:25

Respuestas

  • Hola RamonAZ,

    Como menciona miqui es problema de la configuración regional. Si ingresas 50 * 11,75 el resultado que te mostrará es 587,50.

    Tienes que tener claro que NumberDecimalSeparator vas a usar, el punto o coma decimal.

    - Si usas el punto decimal, puedes hacer :

            Dim ci = CultureInfo.InvariantCulture
            Dim total As Decimal = Decimal.Parse(TxtCosto.Text, ci) * CInt(TxtCantidad.Text)
            total = Math.Round(total, 3)
    
            TextBox1.Text = total.ToString(ci)  '587.50

    U otra forma, si no sabes que separador va a usar el usuario, ya sea coma o punto :

            Dim total As Decimal = CDec(If(TxtCosto.Text.Contains("."),
                                        TxtCosto.Text.Replace(".", ","), TxtCosto.Text)) *
                                    CInt(TxtCantidad.Text)
    
            total = Math.Round(total, 3)
    
            TextBox2.Text = total.ToString  '587,50

    En caso valides mediante el KeyPress, aquí respondí algo similar :

    Permitir solo numeros y simbolo decimal

    Saludos.


    JC NaupaCrispín
    Lima - Perú

    La magia no existe, la programación SI

    domingo, 11 de septiembre de 2016 2:25
  • "RamonAZ" preguntó:

    >  Dim total As Decimal = CDec(TxtCosto.Text) * CDec(TxtCantidad.Text)
    >
    > Y nada... si multiplico 50*11.75 me da 58750
    >
    > No entiendo por que no pone  587.50...

    Hola, Ramón:

    Eso te sucede porque la función de conversión CDec tiene en cuenta la referencia cultural del subproceso actual. Si escribes el punto decimal (.) como separador de decimales en una configuración regional de Windows de español de España, obtendrás el resultado 58750, que sería el mismo que obtendría un usuario con una configuración de inglés de Estados Unidos si teclea la coma decimal (,) como separador de decimales.

    Pero la solución que te ha propuesto Joel C. Naupa Crispín, entiendo que no es del todo correcta, o al menos no lo es para mí, porque si tomas como referencia cultural el valor CultureInfo.InvariantCulture, los usuarios que estén acostumbrados a la coma decimal no estarán trabajando a gusto con tu aplicación. En mi opinión personal, la configuración regional que tenga establecida el usuario "ES SAGRADA", y ya no sé las veces que he escrito que es nuestra aplicación la que se tiene que adaptar a la configuración regional que tenga establecida el usuario en su sistema operativo y no al revés.

    Para salir del paso, la solución pasa por detectar en los evento KeyPress de los controles TextBox el carácter decimal que ha tecleado el usuario, de tal manera que si éste no coincide con el que tiene en su configuración regional cambiarlo por el que figura en la misma.

    Si deseas hacer una prueba, inserta en el formulario que contiene los controles TxtCosto y TxtCantidad el siguiente código, y en el mismo evento que aparece en el ejemplo:

    Imports System.Globalization
    
    Public Class Form1
    
        ' Campos de sólo lectura, para que no se puedan modificar
    ' su valor salvo en el constructor de la clase.
    ' Private ReadOnly m_decimalSeparator As Char Private ReadOnly m_groupSeparator As Char Public Sub New() ' Esta llamada es exigida por el diseñador. InitializeComponent() ' Agregue cualquier inicialización después de la llamada a InitializeComponent(). ' ' Obtener el formato de número existente actualmente en ' el subproceso actual, que normalmente será el que se ' tenga en la configuración regional del sistema operativo. ' Dim numberFormatInfo As NumberFormatInfo = Threading.Thread.CurrentThread.CurrentCulture.NumberFormat ' Carácter separador decimal. m_decimalSeparator = numberFormatInfo.NumberDecimalSeparator.Chars(0) ' Carácter separador de miles. m_groupSeparator = numberFormatInfo.NumberGroupSeparator.Chars(0) End Sub Private Sub TextBoxOnKeyPress(sender As Object, e As KeyPressEventArgs) Handles TxtCosto.KeyPress, TxtCantidad.KeyPress If (e.KeyChar = m_groupSeparator) Then ' El carácter tecleado se corresponde con el carácter separador ' de miles, por lo que lo sustituimos por el carácter separador ' decimal existente actualmente en la configuración regional ' del subproceso actual. ' e.KeyChar = m_decimalSeparator End If End Sub End Class

    De ésta manera, si el usuario tiene una configuración de español, cada vez que teclee el punto (.) se cambiará por una coma, y aquel usuario de Estados Unidos que teclee una coma se cambiará por un punto.

    Si deseas simular una configuración regional independiente de una referencia cultural concreta, en el constructor Sub New, y ANTES de obtener el objeto NumberFormatInfo, inserta la línea que aparece en negrita:

            ' Esta llamada es exigida por el diseñador.
            InitializeComponent()

            ' Agregue cualquier inicialización después de la llamada a InitializeComponent().
            '
            Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture

            ' Obtener el formato de número existente actualmente en
            ' el subproceso actual, que normalmente será el que se
            ' tenga en la configuración regional del sistema operativo.
            '
            Dim numberFormatInfo As NumberFormatInfo = Threading.Thread.CurrentThread.CurrentCulture.NumberFormat

    Lo mismo tienes que recompilar la solución para que ese cambio surta efecto.

    Y cuando quieras multiplicar los valores existentes en los controles TextBox, tan solo te tienes que preocupar que el usuario haya escrito un valor decimal correcto, sin especificar ningún tipo de objeto CultureInfo:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Dim costo As Decimal, cantidad As Decimal
    
            ' Obtenemos un valor Decimal si se ha escrito un valor
            ' Decimal válido en el control TxtCosto.
            '
            If (Not Decimal.TryParse(TxtCosto.Text, costo)) Then
                TxtCosto.Clear()
                MessageBox.Show("No es un valor Decimal válido.")
                Return  ' Abandonar el procedimiento.
            End If
    
            ' Obtenemos un valor Decimal si se ha escrito un valor
            ' Decimal válido en el control TxtCantidad.
            '
            If (Not Decimal.TryParse(TxtCantidad.Text, cantidad)) Then
                TxtCantidad.Clear()
                MessageBox.Show("No es un valor Decimal válido.")
                Return  ' Abandonar el procedimiento.
            End If
    
            Dim total As Decimal = Math.Round(costo * cantidad, 3)
    
            TextBox1.Text = total.ToString()
    
        End Sub

    He comentado anteriormente que con esto sales del paso, pero lo correcto sería que te crearas tu propio control TextBox numérico, o bien, que utilices alguno que ya se encuentre diseñado, como el que en día publiqué en la siguiente conversación:

    Validar que un textbox slo acepte + , - , punto , coma pero solo una vez cada uno???

    Ten en cuenta que en los controles TextBox el usuario puede "pegar" desde el Portapapeles un valor numérico que tienes que verificar si es o no un valor decimal válido, y si lo hace, de nada sirve el código existente en el evento KeyPress de dicho control. ;-)

    Un saludo


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    lunes, 12 de septiembre de 2016 16:25
    Moderador

Todas las respuestas

  • total=FormatNumber(CDbl(txtcosto.text)*CDbl(txtcantidad.text))

    el total debe ser una variable double no decimal
    • Editado cedlcf sábado, 10 de septiembre de 2016 12:18
    sábado, 10 de septiembre de 2016 12:16
  • Hola RamonAZ,

    Como menciona miqui es problema de la configuración regional. Si ingresas 50 * 11,75 el resultado que te mostrará es 587,50.

    Tienes que tener claro que NumberDecimalSeparator vas a usar, el punto o coma decimal.

    - Si usas el punto decimal, puedes hacer :

            Dim ci = CultureInfo.InvariantCulture
            Dim total As Decimal = Decimal.Parse(TxtCosto.Text, ci) * CInt(TxtCantidad.Text)
            total = Math.Round(total, 3)
    
            TextBox1.Text = total.ToString(ci)  '587.50

    U otra forma, si no sabes que separador va a usar el usuario, ya sea coma o punto :

            Dim total As Decimal = CDec(If(TxtCosto.Text.Contains("."),
                                        TxtCosto.Text.Replace(".", ","), TxtCosto.Text)) *
                                    CInt(TxtCantidad.Text)
    
            total = Math.Round(total, 3)
    
            TextBox2.Text = total.ToString  '587,50

    En caso valides mediante el KeyPress, aquí respondí algo similar :

    Permitir solo numeros y simbolo decimal

    Saludos.


    JC NaupaCrispín
    Lima - Perú

    La magia no existe, la programación SI

    domingo, 11 de septiembre de 2016 2:25
  • "RamonAZ" preguntó:

    >  Dim total As Decimal = CDec(TxtCosto.Text) * CDec(TxtCantidad.Text)
    >
    > Y nada... si multiplico 50*11.75 me da 58750
    >
    > No entiendo por que no pone  587.50...

    Hola, Ramón:

    Eso te sucede porque la función de conversión CDec tiene en cuenta la referencia cultural del subproceso actual. Si escribes el punto decimal (.) como separador de decimales en una configuración regional de Windows de español de España, obtendrás el resultado 58750, que sería el mismo que obtendría un usuario con una configuración de inglés de Estados Unidos si teclea la coma decimal (,) como separador de decimales.

    Pero la solución que te ha propuesto Joel C. Naupa Crispín, entiendo que no es del todo correcta, o al menos no lo es para mí, porque si tomas como referencia cultural el valor CultureInfo.InvariantCulture, los usuarios que estén acostumbrados a la coma decimal no estarán trabajando a gusto con tu aplicación. En mi opinión personal, la configuración regional que tenga establecida el usuario "ES SAGRADA", y ya no sé las veces que he escrito que es nuestra aplicación la que se tiene que adaptar a la configuración regional que tenga establecida el usuario en su sistema operativo y no al revés.

    Para salir del paso, la solución pasa por detectar en los evento KeyPress de los controles TextBox el carácter decimal que ha tecleado el usuario, de tal manera que si éste no coincide con el que tiene en su configuración regional cambiarlo por el que figura en la misma.

    Si deseas hacer una prueba, inserta en el formulario que contiene los controles TxtCosto y TxtCantidad el siguiente código, y en el mismo evento que aparece en el ejemplo:

    Imports System.Globalization
    
    Public Class Form1
    
        ' Campos de sólo lectura, para que no se puedan modificar
    ' su valor salvo en el constructor de la clase.
    ' Private ReadOnly m_decimalSeparator As Char Private ReadOnly m_groupSeparator As Char Public Sub New() ' Esta llamada es exigida por el diseñador. InitializeComponent() ' Agregue cualquier inicialización después de la llamada a InitializeComponent(). ' ' Obtener el formato de número existente actualmente en ' el subproceso actual, que normalmente será el que se ' tenga en la configuración regional del sistema operativo. ' Dim numberFormatInfo As NumberFormatInfo = Threading.Thread.CurrentThread.CurrentCulture.NumberFormat ' Carácter separador decimal. m_decimalSeparator = numberFormatInfo.NumberDecimalSeparator.Chars(0) ' Carácter separador de miles. m_groupSeparator = numberFormatInfo.NumberGroupSeparator.Chars(0) End Sub Private Sub TextBoxOnKeyPress(sender As Object, e As KeyPressEventArgs) Handles TxtCosto.KeyPress, TxtCantidad.KeyPress If (e.KeyChar = m_groupSeparator) Then ' El carácter tecleado se corresponde con el carácter separador ' de miles, por lo que lo sustituimos por el carácter separador ' decimal existente actualmente en la configuración regional ' del subproceso actual. ' e.KeyChar = m_decimalSeparator End If End Sub End Class

    De ésta manera, si el usuario tiene una configuración de español, cada vez que teclee el punto (.) se cambiará por una coma, y aquel usuario de Estados Unidos que teclee una coma se cambiará por un punto.

    Si deseas simular una configuración regional independiente de una referencia cultural concreta, en el constructor Sub New, y ANTES de obtener el objeto NumberFormatInfo, inserta la línea que aparece en negrita:

            ' Esta llamada es exigida por el diseñador.
            InitializeComponent()

            ' Agregue cualquier inicialización después de la llamada a InitializeComponent().
            '
            Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture

            ' Obtener el formato de número existente actualmente en
            ' el subproceso actual, que normalmente será el que se
            ' tenga en la configuración regional del sistema operativo.
            '
            Dim numberFormatInfo As NumberFormatInfo = Threading.Thread.CurrentThread.CurrentCulture.NumberFormat

    Lo mismo tienes que recompilar la solución para que ese cambio surta efecto.

    Y cuando quieras multiplicar los valores existentes en los controles TextBox, tan solo te tienes que preocupar que el usuario haya escrito un valor decimal correcto, sin especificar ningún tipo de objeto CultureInfo:

        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    
            Dim costo As Decimal, cantidad As Decimal
    
            ' Obtenemos un valor Decimal si se ha escrito un valor
            ' Decimal válido en el control TxtCosto.
            '
            If (Not Decimal.TryParse(TxtCosto.Text, costo)) Then
                TxtCosto.Clear()
                MessageBox.Show("No es un valor Decimal válido.")
                Return  ' Abandonar el procedimiento.
            End If
    
            ' Obtenemos un valor Decimal si se ha escrito un valor
            ' Decimal válido en el control TxtCantidad.
            '
            If (Not Decimal.TryParse(TxtCantidad.Text, cantidad)) Then
                TxtCantidad.Clear()
                MessageBox.Show("No es un valor Decimal válido.")
                Return  ' Abandonar el procedimiento.
            End If
    
            Dim total As Decimal = Math.Round(costo * cantidad, 3)
    
            TextBox1.Text = total.ToString()
    
        End Sub

    He comentado anteriormente que con esto sales del paso, pero lo correcto sería que te crearas tu propio control TextBox numérico, o bien, que utilices alguno que ya se encuentre diseñado, como el que en día publiqué en la siguiente conversación:

    Validar que un textbox slo acepte + , - , punto , coma pero solo una vez cada uno???

    Ten en cuenta que en los controles TextBox el usuario puede "pegar" desde el Portapapeles un valor numérico que tienes que verificar si es o no un valor decimal válido, y si lo hace, de nada sirve el código existente en el evento KeyPress de dicho control. ;-)

    Un saludo


    Enrique Martínez Montejo
    [MS MVP - Visual Studio y Tecnologías de Desarrollo]

    Nota informativa: La información contenida en este mensaje, así como el código fuente incluido en el mismo, se proporciona «COMO ESTÁ», sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo recomendado o sugerido en el presente mensaje.

    Si esta respuesta le ha resultado útil, recuerde marcarla como satisfactoria.

    Si usas Visual Basic .NET y deseas ser productivo y feliz, se inteligente y activa la instrucción
    Option Strict.


    lunes, 12 de septiembre de 2016 16:25
    Moderador