Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Conexión con bases de datos
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Conexión con bases de datos

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 15-06-2003
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Thumbs up dichoso separador decimal

Hola a todos.

He rescatado este mensaje del historico de los foros unicamente con el proposito de "cerrarlo" y aclarar el tema del todo.

En el hilo original preguntaba lo siguiente:
Cita:
Posteado originalmente por Lepe
Holassss.........

El problema que tengo es que no me deja escribir el punto decimal en los controles DBAware de delphi.

al arrancar el programa, pregunto cual es el separador, y me dice que es la coma, así que hago esto:
Código:
   sysutils.CurrencyDecimals:=2; 

   sysutils.decimalseparator:='.'; 

   sysutils.thousandseparator:=',';
Al entrar en un control DB nativo de delphi, pregunto de nuevo cual es el separador decimal, y me responde que es el punto; entonces, ¿Por qué no me deja escribirlo?, unicamente me deja escribir la coma, y por tanto, al salir del control DB, me da el error de que el número con la coma no es un Tfloat válido.
Cita:
Posteado originalmente por andres1569
Hola Lepe:

He investigado un ratito y he llegado a las conclusiones siguientes:

La configuración del BDE no sirve de nada, de hecho ni siquiera afecta al Database Desktop, sino que sigue lo que hayamos definido en la Configuración Regional del Panel de Control, lo mismo que los controles DBAware.

Las propiedades DisplayFormat y EditFormat utilizan "siempre" la coma como indicador de separador de millares, y el punto como separador decimal, por lo que al rellenar estas propiedades le estamos indicando si queremos incluirlos y en el caso del separador decimal en qué posición (nº de decimales), pero "nunca" le estamos indicando qué caracter queremos usar para cada cosa.

La única forma de sobreecribir esas variables de entorno es mediante ThousandSeparator y DecimalSeparator. ¿Qué ocurre? Que al cambiarlas afectan a la visualización, de hecho tú sí ves el punto como separador decimal pero no te deja introducirlo, y la coma sí.

SOLUCION: Urgando en el código te enteras de que los controles DBAware, al comprobar si una tecla es válida llaman al método IsValidChar del campo relacionado TField, ese método comprueba si la tecla está permitida según el tipo de campo (difiere de un Integer a un Float ...) mirando una cadena de caracteres que es inicializada cuando se crea el campo en cuestión y que SÍ mira el DecimalSeparator; lo que ocurre es que cuando se crean estos objetos TField, tú aún no has cambiado esas variables de entorno; por lo tanto los campos que se creen antes de asignar tú por código esta variable se comportarán de forma diferente a los creados después, por ejemplo los que se crean dinámicamente en ejecución. Como solución he creado una unit que hace esto:


Código:
UnitAnticipa; 

interface 

uses SysUtils; 

implementation 

initialization 
  ThousandSeparator  := ','; 
  DecimalSeparator := '.'; 

end;
Ahora en el MainForm declaro esa unit justo detrás de SysUtils y entonces sí me coge esas variables como yo quiero incluso antes de que se creen los controles DBAware (había probado en el OnCreate del form, y poniendo OldCreateOrder a TRUE, pero no funcionaba).

Un saludo

La solución de crear una unit aparte puede ser excesiva, es posible que poniendo lo mismo en la sección Initialization del DataModule principal, o incluso en mismo archivo .dpr ya sirva.

Saludos
Exacto Andres, poniendolo en la inicialización del datamodule ya funciona.
Código:
initialization
  ThousandSeparator  := ',';
  DecimalSeparator := '.';

Esta última es la aclaración que queria hacer

Gracias andres
Responder Con Cita
  #2  
Antiguo 16-06-2003
andres1569 andres1569 is offline
Miembro
 
Registrado: may 2003
Posts: 908
Poder: 21
andres1569 Va por buen camino
Pues, con tu permiso, Lepe, voy a reabrir el hilo.

A raíz de aquel mensaje tuyo, me quedé pensando si la razón de querer mostrar al usuario los números con "punto" para separación decimal tenía que ver con que el usuario de tu programa era algún residente extranjero que quería ver las cantidades "como en su país", pero por otra parte aclarabas que no querías tener que cambiarle la configuración regional a nivel de SO, lo cual me extrañó.

Pensándolo un poco me he acordado de que con la llegada del Euro se ha popularizado el uso de los decimales, y muchos usuarios, sobre todo contables, demandan poder usar el punto del teclado numérico como lo que es, un separador decimal, pero si nuestro control DBAware sólo admite "comas", eso no es posible. Si éste es tu caso, la solución de cambiar el DecimalSeparator deja como efecto secundario el que las cantidades se muestren de forma distinta a lo habitual (es decir, a la americana), aunque consiga dar validez a dicho punto.

De las varias soluciones que pensé para solucionarlo, la que me parece más acertada es la de interceptar la pulsación del punto decimal y transformarlo en una coma. Crear nuevos componentes heredados de los DBAware para controlar esto es "demasiao", más aún cuando habría que redefinir DBGrids, DBEdits ... etc, y no se me ocurre una forma mejor. Así que aquí va lo que tengo implementado:

Código:
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
  if MapearPuntoAComa AND (Msg.message = WM_KEYDOWN) AND 
     (Msg.wParam = VK_DECIMAL) AND (DecimalSeparator = ',') then 
  begin
    Msg.message := WM_CHAR;   // cambiamos el tipo de mensaje
    Msg.wParam := 44;  // si omitimos la línea anterior, aquí sería Msg.wParam := 188;  
    Handled := FALSE;
  end;
end;
Colocamos un TApplicationEvents (a partir de Delphi 5, en Delphi 4 o anterior hay que hacerlo a mano) e interceptamos el evento OnMessage.

Con esto, si tenemos la variable global MapearPuntoAComa a TRUE y se pulsa el . del teclado numérico, transformamos ese mensaje en uno que envía una coma, y asunto resuelto. En este caso he cambiado el tipo de mensaje de WM_KEYDOWN a WM_CHAR, la razón es que así le puedo asignar la coma directamente (ASCII 44). Si dejara el mensaje como WM_KEYDOWN, debería asignar el código ASCII 188, que es la tecla que genera la coma, pero esto sólo valdría para los "teclados españoles".

Si alguien tiene alguna sugerencia sobre este tema, o lo ha resuelto de otro modo, bienvenida sea otra solución, seguro que a casi todos se os ha planteado esta cuestión.
__________________
Guía de Estilo
Responder Con Cita
  #3  
Antiguo 16-06-2003
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Cita:
Posteado originalmente por andres1569
Pues, con tu permiso, Lepe, voy a reabrir el hilo.
Todo un honor

Cita:
Posteado originalmente por andres1569
[...] con la llegada del Euro se ha popularizado el uso de los decimales, y muchos usuarios, sobre todo contables, demandan poder usar el punto del teclado numérico como lo que es [...]
Exacto, diste en el clavo de nuevo.

Pues, con su permiso, Andres, voy a usar el nuevo método
Responder Con Cita
  #4  
Antiguo 19-04-2004
Avatar de marcoszorrilla
marcoszorrilla marcoszorrilla is offline
Capo
 
Registrado: may 2003
Ubicación: Cantabria - España
Posts: 11.221
Poder: 10
marcoszorrilla Va por buen camino
Muy interesante la solución de Andrés, yo hasta el momento lo resolvía interceptando la pulsación
de la tecla en el control correspondiente lo cual me llevaba a propagar el código ad infinitum, tantos
controles afectados tantos eventos a programar o en su caso llamadas a una función centralizada.


Como el applicationsEvents se dispara a cada momento, la variable semáforo propuesta por Andrés,
entiendo que habría que abrirla solamente en los formularios en los cuales se fuese a dar ese
tratamiento de cambio de punto por coma del teclado numérico.

Y si estais de acuerdo en lo dicho entonces yo propondría el siguiente leve cambio en el código:

Código:
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin
  if MapearPuntoAComa then//Sino está activado salir cuanto antes.
  begin
    if (Msg.message = WM_KEYDOWN) AND
     (Msg.wParam = VK_DECIMAL) AND (DecimalSeparator = ',') then
      begin
      ShowMessage('Aquí estamos Andrés.');
        Msg.message := WM_CHAR;   // cambiamos el tipo de mensaje
        Msg.wParam := 44;  // si omitimos la línea anterior,
 aquí sería Msg.wParam := 188;
        Handled := FALSE;
    end;
  end;
end;
A ver que os parece, con el permiso de Andrés.

Un Saludo.
__________________
Guía de Estilo de los Foros
Cita:
- Ça c'est la caisse. Le mouton que tu veux est dedans.

Última edición por marcoszorrilla fecha: 19-04-2004 a las 16:01:48.
Responder Con Cita
  #5  
Antiguo 19-04-2004
andres1569 andres1569 is offline
Miembro
 
Registrado: may 2003
Posts: 908
Poder: 21
andres1569 Va por buen camino
Aclarar que el código que modificas, Marcos, hace lo mismo que el que puse si está desactivada la directiva de comprobación booleana (ahora no recuerdo la letra de la directiva, su nombre es Complete Boolean Evaluation, es la que se encarga de abortar las comprobaciones cuando el resultado ya está claro, por eso MapearPuntoAComa está puesto en primer lugar, de forma que si es FALSE, sale del IF, es porque suelo tener dicha directiva para actuar de esa manera). Para evitar dependencias de directivas, conviene hacer lo que planteas, o bien poner la directiva delante de dicho código.

Pero, con tu permiso, Marcos, hay algo que me preocupa a nivel personal, y es que me estoy imaginando a vuestros clientes ladrando por el teléfono, con frases despectivas hacia mí, del tipo:

"¿Quién k*ñ* es este Andrés que aparece cada vez que quiero meter una cantidad con decimales?"

Lo digo por el ShowMessage ése, creo que resta eficiencia al asunto
__________________
Guía de Estilo

Última edición por andres1569 fecha: 19-04-2004 a las 19:46:24.
Responder Con Cita
  #6  
Antiguo 19-04-2004
Avatar de marcoszorrilla
marcoszorrilla marcoszorrilla is offline
Capo
 
Registrado: may 2003
Ubicación: Cantabria - España
Posts: 11.221
Poder: 10
marcoszorrilla Va por buen camino
De acuerdo Andrés, lo puse en la primera entrada, es decir debajo de MapearPuntoAcoma, para comprobar como es lógico que el evento se produce compulsivamente, por lo tanto es lógico desactivar la variable global también al salir de los formularios que la necesitan porque sino la continua evaluación puede restar velocidad a la aplicación.

En este caso como bien dices el cambio propuesto no tendría objeto ya que pusiste en primer lugar esa comprobación con lo cual al no cumplirse no evaluaría el resto.

Un Saludo.
__________________
Guía de Estilo de los Foros
Cita:
- Ça c'est la caisse. Le mouton que tu veux est dedans.
Responder Con Cita
  #7  
Antiguo 19-04-2004
Avatar de guillotmarc
guillotmarc guillotmarc is offline
Miembro
 
Registrado: may 2003
Ubicación: Huelva
Posts: 2.638
Poder: 23
guillotmarc Va por buen camino
Hola.

Yo lo tenía más fácil ya que en mis aplicaciones, en lugar de tener TDbEdits tengo unos componentes propios heredados del mismo (tienen un par de características propias, como que con el ENTER saltan al siguiente control, etc. ...).

Así que añadí una nueva propiedad a mi TIdEditAvancat, llamada PuntsPerComes. Si la activo, cada vez que el usuario pulsa un punto en el control, es reemplazado por una coma.

Código:
procedure TIdEditAvancat.KeyPress(var key: char);
begin
  if FIntroPerTabulador then begin
	if key = #13 then begin
	  key := #0;
	  PostMessage( GetParentForm(Self).Handle, WM_NEXTDLGCTL,0,0 );
	end;
  end;
  if FPuntsPerComes then if Key = '.' then Key := ',';
  if key <> #0 then inherited KeyPress(key);
end;
NOTA: He dejado también el código que cambia el ENTER por un TABULADOR.

Saludos.
__________________
Marc Guillot (Hi ha 10 tipus de persones, els que saben binari i els que no).

Última edición por guillotmarc fecha: 19-04-2004 a las 21:41:37.
Responder Con Cita
  #8  
Antiguo 19-04-2004
Avatar de marcoszorrilla
marcoszorrilla marcoszorrilla is offline
Capo
 
Registrado: may 2003
Ubicación: Cantabria - España
Posts: 11.221
Poder: 10
marcoszorrilla Va por buen camino
Cita:
Use the $B compiler directive to control evaluation mode. The default state is {$B–}, which enables short-circuit evaluation. To enable complete evaluation locally, add the {$B+} directive to your code. You can also switch to complete evaluation on a project-wide basis by selecting Complete Boolean Evaluation in the Compiler Options dialog.
La rectificación por mi propuesta carece de sentido de acuerdo a la explicación dada por Andrés y además aquí esta la ayuda de Delphi que según se observa por defecto hace una evaluación lógica de tipo breve, es decir que en el momento que no coincida la comparación abandona el resto y como Andrés explicó la variable MapearPuntoAComa está en primer lugar.

Un Saludo.
__________________
Guía de Estilo de los Foros
Cita:
- Ça c'est la caisse. Le mouton que tu veux est dedans.
Responder Con Cita
  #9  
Antiguo 19-04-2004
Avatar de guillotmarc
guillotmarc guillotmarc is offline
Miembro
 
Registrado: may 2003
Ubicación: Huelva
Posts: 2.638
Poder: 23
guillotmarc Va por buen camino
Hola.

Cita:
Empezado por marcoszorrilla
La rectificación por mi propuesta carece de sentido de acuerdo a la explicación dada por Andrés y además aquí esta la ayuda de Delphi que según se observa por defecto hace una evaluación lógica de tipo breve, es decir que en el momento que no coincida la comparación abandona el resto y como Andrés explicó la variable MapearPuntoAComa está en primer lugar.
Hola, concretamente se llama evaluación perezosa (en inglés es más habitual encontrarla como lazy evaluation). Siempre me ha gustado mucho este nombre.

Saludos.
__________________
Marc Guillot (Hi ha 10 tipus de persones, els que saben binari i els que no).
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro


La franja horaria es GMT +2. Ahora son las 12:21:44.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi