Despedida de Andreano Lanusse

A todos nos ha pillado por sorpresa la triste noticia: Andreano dice adiós a Embarcadero. El mis

Taller práctico – EditMask y TFormatSettings

Hola a todos, estamos de vuelta, nuevamente,  tras un pequeño periodo de ausencia, motivado princi

Embarcadero (Videos del webinar de 1 de Marzo)

Diseñe aplicaciones web para móviles y aplicaciones nativas para iOS, Android y más con RAD Studi

 

Despedida de Andreano Lanusse

mayo 2, 2012 en Delphi Prism, Entrada Diario, Nos deja la semana..., Noticias, Noticias Delphi

A todos nos ha pillado por sorpresa la triste noticia: Andreano dice adiós a Embarcadero.

El mismo nos lo comentaba a través de uno de sus blogs.

http://www.andreanolanusse.com/en/bye-bye-embarcadero/

Andreano Lanusse

 

Coincido con mis compañeros en que hoy es un día triste para nuestra Comunidad y desde este blog, participando del mismo sentimiento e inquietudes, quisiera darle las gracias públicamente a Andreano, por el gran apoyo a la Comunidad Hispana que ha supuesto su trabajo en las distintas presentaciones, videos, recursos escritos y en general su presencia en la red desde hace tantos años.

Se que es difícil valorar eso cuando siempre nos hemos quejado de la falta de sensibilidad hacia nuestra Comunidad. Pero seria injusto no reconocer que existió un punto de inflexión claramente definido con la llegada a Delphi de Embarcadero y un cambio que no hubiera sido posible sin Andreano. Gran trabajo, Andreano. ¡Gran trabajo el tuyo!.

Se abren muchas interrogantes. Y muchos compañeros se preguntan si realmente Embarcadero ha valorado esta decisión y las consecuencias que puede tener. Personalmente, me apenaría intuir que una decisión como ésta sea al final fruto de un mero enfoque de frió mercantilismo por parte de los accionistas de Embarcadero, por la falta de respeto que supone a los esfuerzos que durante años se han hecho por la continuidad de la Comunidad Hispana y del espíritu de Delphi. Porque muchos de nostros veíamos en el aporte de Andreano la semilla de crecimiento de la Comunidad.

Solo me resta desearle a Andreano muy buena suerte en la nueva andadura y recordarle que aunque no he tenido el placer de conocerle, le guardo en estima y le deseo lo mejor.

Gracias por todo, Andreano.

Taller práctico – EditMask y TFormatSettings

abril 17, 2012 en Artículos, Delphi, Entrada Diario, Taller práctico, ¿Sabías que...?, ¿Sabías que...? [Delphi]

Hola a todos,

estamos de vuelta, nuevamente,  tras un pequeño periodo de ausencia, motivado principalmente por temas de trabajo, aunque también os confieso, por asuntos relacionados con nuestra Comunidad. Aunque suene misterioso… ésto, dicho así, no tiene nada de misterio sino que hace referencia a la buena relación de muchos de los compañeros y amigos que colaboramos activamente y que nos lleva a proponer iniciativas y a compartir inquietudes para mejorar nuestra Comunidad. Estamos en ello y supongo que algún día veremos sus frutos. El hecho de que alguien “pierda” su tiempo pensando en cómo mejorar nuestro espacio y nuestros recursos ya es prometedor en si mismo.

De hecho, la tipología de esta entrada responde a una de esas inquietudes que me planteaba durante estos meses pasados y que me lleva a rescatar las lineas que hablaban de las cosas básicas, desde un punto de vista práctico y sencillo, como augura el título de “taller”, recuperando el espacio para aquellos contenidos  dirigidos a las personas que dan sus primeros pasos en el entorno. Y quizás por eso, no hablaban de las ultimas novedades sino de temas que afectan a nuestro trabajo diario.

Así que van a convivir unas y otras en el blog, compartiendo el espacio y mi tiempo. Creo que son cosas compatibles.

Estos primeros meses del año han traído algunas alegrías y también algunos sinsabores. Como alegrías cuento por ejemplo el que el grupo de facebook Delphi Solidario crezca y vaya tomando mas fuerza, como medio de compartir el día a día y las noticias de las últimas publicaciones, aspecto que es favorecido por la dinámica que aporta la red social y su inmediatez . Iniciamos el año con el objetivo de al menos llegar a 200 personas y ya superamos esa cifra. Y no dudo que durante todo este año quizas la doblemos (ehhhhh ¡veis que no perdí mi optimismo!) :-)   Lo que mas cuesta es quizás ser constante y buscar cada mañana las novedades,  (aunque no sean en nuestra propia lengua) pero creo que vale la pena ese esfuerzo, aunque haya tenido como contrapartida que se ha visto reducido mi tiempo disponible para el blog.

También fue una alegría que viese la luz la última publicación en español sobre XE2, de la mano de F. Charte, autor de sobra conocido por todos nosotros y cuyo libro nos brinda una perspectiva amplia sobre la última versión de nuestra herramienta. Yo como muchos otros compañeros, me he sumado a quienes recomendaron su lectura y lo he hecho exhibiendo en varias partes de mis paginas la noticia de su publicación. El libro puede ser adquirido a través de Danysoft y como podéis ver en la foto, también me hice con uno de los ejemplares. No quise ser menos que mi amigo Germán y aquí tenéis la foto de rigor.  

La Guía de Dephi

¡Yo también voy a leer la Guía de Delphi!

En la parte negativa, seguro que ya os disteis cuenta que perdimos las páginas inestimables del Rinconcito Delphi, de nuestro amigo Jose Luis Freire,  que desde el 18 de Febrero cerró sus ventanas a la Red y nos dejó a muchos de nosotros la tristeza de ir perdiendo parte de nuestra historia como Comunidad. Quienes la han vivido, saben de lo que hablo y solo puedo decir en ese sentido que yo me he sentido especialmente triste por cuanto he colaborado con él en algunas de esas páginas que se escribieron, iniciativas que se llevaron a cabo (boletín de delphi, artículos añadidos procedentes de Sintesis, etc…) durante varios años. De momento reza el cartel de hasta aquí llegamos en su cabecera pero…

:-)

ya os he anticipado que el hecho de que exista un núcleo de personas que siguen apostando por la Comunidad es algo prometedor. Y tan pronto como sepa el final de esta historia y si tiene un final feliz, seréis los primeros en saberlo.

Lo dejamos ahí para centrarnos en nuestro taller, que aborda hoy un tema muy básico sobre mascaras de edición y rutinas de conversión de tipos.

Aunque me haya referido de forma conjunta en el título de la entrada, en principio no hay una correlación directa entre  EditMask y TFormatSettings. Veamos… Son cosas distintas: EditMask es una propiedad que hace referencia al editor de máscara para un determinado control de edición en la interfaz de nuestro usuario, y por tanto, establece qué caracteres serán validos entre los que va a proporcionar el usuario al escribir sobre la casilla de edición y cómo se disponen. Se podría decir que forzamos a que se ajusten a una regla previamente convenida y se busca facilitar su inserción, dado que existen parte de los caracteres que pueden ser omitidos, aunque figuren finalmente en el texto de la entrada. Es el caso por ejemplo de las barras de los formatos de fechas (__/__/___), que habitualmente se evita que  el usuario rellene, ganando en la comodidad de evitar su escritura, aun cuando figuren finalmente en la fecha. O el hecho de que garanticemos una única forma de escribir un DNI sin que el usuario se plantee si tiene que introducir el valor asociado intercalando puntos o sin ellos, con guión o sin guión, que puede ser motivo de que un mismo dato pueda ser escrito de forma distintas y generar exclusiones en las búsquedas o errores. Ese es el propósito de las máscaras.

Por el contrario, TFormatSettings es una estructura, un registro, que recoge información relacionada con el usuario y su localización (formato de fecha, separadores decimales y de millares, numero de decimales en uso, formato en cantidades negativas, moneda, etc) datos que son propios de la instalación del sistema y que se han configurado de acuerdo a las preferencias locales o del usuario.

TFormatSettings puede ser utilizada opcionalmente en algunas de las rutinas de conversión existentes en la unidad SysUtils, algo que nos ayudará en la tarea de convertir los tipos de dato fecha y decimal, a los que harán referencia muchas de nuestras máscaras. Esa es la razón que me ha hecho pensar en la conveniencia de que ambas compartieran esta entrada.

type TFormatSettings = record
	CurrencyFormat: Byte;
	NegCurrFormat: Byte;
	ThousandSeparator: Char;
	DecimalSeparator: Char;
	CurrencyDecimals: Byte;
	DateSeparator: Char;
	TimeSeparator: Char;
	ListSeparator: Char;
	CurrencyString: string;
	ShortDateFormat: string;
	LongDateFormat: string;
	TimeAMString: string;
	TimePMString: string;
	ShortTimeFormat: string;
	LongTimeFormat: string;
	ShortMonthNames: :TFormatSettings.:1;
	LongMonthNames: :TFormatSettings.:2;
	ShortDayNames: :TFormatSettings.:3;
	LongDayNames: :TFormatSettings.:4;
	TwoDigitYearCenturyWindow: Word;
     end;

En la parte superior, veis la estructura tal y como se define en Delphi. Los campos del registro son variados y en gran medida relacionados con la temporalidad y las distintas presentaciones de los formatos de fecha, aunque también contiene, como anticipábamos, campos relacionados con la presentación del formato decimal o de la moneda.

Ejemplos de posibles máscaras podrían ser “###0.00;1;_”, que permitiría insertar al usuario un numero de cuatro cifras y que nos muestre dos de sus decimales . O también podría ser la mascara de una cantidad monetaria (“#,##0.00 €;1;_”) que formatearía la entrada con un separador de millares,  un separador decimal y el símbolo de la moneda.

En cualquier caso, el guión nos dice que una vez introducidas por nuestro usuario, serán convertidas en un momento posterior a su tipo adecuado, que nos permitirá hacer las operaciones necesarias a efectos de obtener lo que sea. Así pues, en esa conversión  podríamos valernos de algunas funciones existentes en la unidad SysUtils, como StrToFloat( ) o TryStrToFloat( ) para convertir el texto, y ambas pueden utilizar la estructura TFormatSettings para efectuar correctamente dicha conversión.

Esa es la relacion que podemos observar entre la propiedad EditMask y TFormatSettings, que puede pasar inadvertida y ésto es una de las razones que me movió a escribir la entrada.

Pondré un ejemplo de por qué  me parece interesante compartir este comentario, especialmente con los compañeros que se inician en Delphi. Usemos nuestra imaginación e imaginemos un escenario muy sencillo, una interfaz que contiene un botón y un componente TMaskEdit, con una de las máscaras citadas anteriormente. Por ejemplo:  “###0.00;1;_”. El usuario introduce una cantidad cualquiera, 1234.56 y la pulsación del botón produce la ejecución de un proceso X que utiliza dicho valor.

procedure HazAlgoConLaCantidad(const MiCantidad: string);

Es de lógica, que en algún lugar de la implementación de esta función nos vamos a plantear la conversión de la cadena de texto a su tipo correcto, pudiendo usar las funciones StrToFloat( ) para ello. Hagamos algo como fvalor:= StrToFloat(maskinterfaz.Text); donde fValor es una variable de tipo Double y StrToFloat( ) la función que recibe como parámetro el texto de la entrada, formateado previamente por la mascara impuesta, y devuelve su valor convertido. Nos podemos sentir muy seguros y confiados. El usuario no va a poder introducir otra cosa distinta de la que nos marca la máscara y la conversión parece fiable. Nada puede pasar…

Y quizás lo peor que nos puede suceder es que esta conversión funcione  fruto de la casualidad de que el separador decimal usado en nuestra máscara coincida con el predefinido por el sistema, porque la función que nos ha permitido la conversión sí ha buscado este último para llevarla a cabo. Ese es el peor escenario y nuestro código queda expuesto potencialmente a sufrir un error de conversión de tipos que se puede dar en cualquier momento posterior en los equipos de nuestros usuarios. Quizás no valoramos que otros programas podrían interferir sobre la selección del punto decimal o de la coma como separador decimal. O quizás la localización de los usuarios de nuestra aplicación cambió, modificándose las preferencias de los sistemas en los que se ejecuta nuestro programa.

Estos comentarios pueden extrapolarse en gran medida a las conversiones de fecha también. Nuestra actitud debería ser  la de extremar la prudencia y no dar como supuesto algo que fácilmente puede cambiar.

El tipo TEditMask

Este tipo, representa la máscara que valida y formatea los caracteres de la entrada del usuario. Es un string o cadena que contiene 3 campos diferenciados, separados por puntos y comas (;). En primer lugar, expone la mascara en si misma (los caracteres válidos y las posiciones que ocupan). El segundo campo nos sirve para saber si las partes literales de la máscara van a ser guardadas o por el contrario se ignorarán. Y finalmente, el tercer campo nos informa sobre qué símbolo se mostrará en aquellos caracteres (opcionales o requeridos) de la entrada que no fueron rellenos y que el usuario puede dar valor; habitualmente se utiliza el guión bajo ( _ ). Es tan habitual que ya no damos importancia a las edición formateada de la fecha y los usuarios requieren cualquier facilidad que les facilite su trabajo. Aunque esa facilidad solo suponga que les evites la pulsación de una barra separadora. :-)

Aunque podemos usar cualquier carácter en la máscara, algunos tienen un significado especial.

  • ! –  Puede ir presente y de ser así, los caracteres opcionales situados al inicio que no se rellenaron, se omitirán del texto que muestra el resultado. Si está presente, los considerará, aunque ignoraria los posteriores no rellenos.  Este es quizás el carácter especial que queda mas oscuro y entiendo que es porque depende de que el segundo campo sea cero (que no guarde literales). Os pido que nos detengamos un poco mas en su explicación y lo veamos con un ejemplo.
    Suponemos una máscara en la que se disponen cuatro caracteres opcionales, 2 literales y el carácter !  “!(aaaa);0;_“. Y suponemos que nuestro usuario tecleó el carácter “2″ en la posición 4, lo cual supone que rellenó solo uno de los caracteres opcionales. Es decir, la entrada muestra “(__2_ )” pero ha procesado el valor resultante como “2 ” (de longitud 2). Es decir, ignoró los literales y de los opcionales se quedó aquellos no rellenados posteriores al carácter tecleado por el usuario.
    Sin embargo, si consideráramos la máscara   “(aaaa);0;_” con el mismo input por parte de nuestro usuario, el resultado de su proceso seria distinto. Seguiría mostrando en nuestro interfaz  “(__2_ )” pero el valor resultante sería ”  2″ (de longitud 3). Es decir, consideraría los espacios no introducidos por el usuario previos al carácter e ignoraría los posteriores (el carácter opcional no relleno).
  • > –  Si el carácter > aparece en la máscara, los caracteres que le siguen serán convertidos a mayúsculas hasta el final de la máscara o sea encontrado el carácter <.
  • < – Consideramos de forma similar a la opción anterior pero en este caso los caracteres son convertidos a minúsculas hasta que el caracter > es encontrado o nos situamos al final de la mascara
  • <>  -Lo usamos si queremos que no sea considerado el caso y se formatee la entrada tal y como la escribió el usuario.
  • \  Este caracter nos permite usar los carácteres especiales como literales por lo que cualquier carácter especial precedido de \ se convierte en un literal.
  • L – El carácter L requiere un carácter alfabético en la posición en que aparece en la máscara. Admitiría los existentes entre [A-Z]  y[ a-z].
  • l  - El carácter l (L minúscula) permite igualmente un carácter alfabético pero en este caso es opcional.
  • A – El carácter A requiere un caracter alfanumérico en la posición en que aparece en la máscara, por lo que ademas de los caracteres alfabéticos ([A-Z], [a-z]) se amplía a los numéricos, [0-9].
  • a – El mismo caso que el anterior pero es opcional.
  • C – Permite un carácter arbitrario en la posición de la máscara.
  • c  – Permite un carácter arbitrario pero es opcional por lo que no es requerido.
  • 0 – El carácter 0 requiere un carácter numérico en la posición.
  • 9 – El carácter 9 permite un numero pero no lo requiere.
  • # – A diferencia del anterior, además de un carácter numérico permite los signos (+/-) siendo igualmente opcionales.
  • :   – Es el separador de horas, minutos y segundos en los formatos de tiempo y si es diferente del predefinido por el sistema, éste es usado en su lugar.
  • /  – Al igual que el anterior, el caracter / se usa para separar meses, días y años en las fechas. De igual forma, si difiere del predefinido por nuestro sistema, éste ultimo es considerado en su lugar.
  • ;  – El carácter especial ; es usado internamente para separar los campos de la máscara. Hacíamos referencia a estos campos al inicio de esta sección al hablar de la máscara en si misma, la posibilidad de guardar los literales o el carácter que consideramos como “blanco” (los que no han sido rellenos por el usuario).
  • _ - Finalmente, el carácter _ permite insertar automáticamente los espacios en el texto.
En la dockwiki de Embarcadero existe un ejemplo sobre trabajo con máscaras que podeis consultar: http://docwiki.embarcadero.com/CodeSamples/en/EditMask_(Delphi) pero creo que son bastante intuitivos los que aparecen en el editor. El tipo de construcciones que podemos considerar no pueden lógicamente tener la complejidad que nos dan las expresiones Regulares (http://www.sjover.com/delphi/?s=expresiones+regulares), tema que ya abordamos anteriormente en varias entradas. Son reglas sencillas de interpretar y conocer, si son comparadas con la potencia que nos ofrecen la validación de texto usando expresiones.
 
El principal exponente o representante del uso de las mascaras de edición no puede ser otro que un componente que cuente con las capacidades de edición y que además extienda las propias del uso referido. Es nuestro TMaskEdit, existente desde siempre en la paleta Additional de nuestra colección de componentes.  La propiedad EditMask (de tipo TEditMask), también está disponible en la clase TField por lo que las mascaras son susceptibles de ser usadas para validar la entrada en los campos de datos. Se supone que nuestro interfaz en ese caso contaría con un componente como  TDBEdit, que puede recibir la entrada de nuestro usuario para validar el texto introducido.
 
Sea como sea, la perdida del foco en la edición, dispara el proceso de validación del texto introducido por el usuario de forma que se evalúe si responde a la máscara requerida. Si es correcto, seguimos nuestro camino. Y si no lo es, se genera una excepción donde advertimos que el texto no la cumple, retornando el foco al control de edición, de forma que pueda ser corregido por el usuario.
 
Hablamos de aspectos tan básicos que creo recordar el editor en tiempo de diseño en el ide, en todas las versiones que he conocido y no cambió desde entonces. Luce este aspecto en Delphi 2010, que es el entorno en el que he hecho el código que acompaña esta entrada.
 
Editor de la propiedad TEditMask
 
La sencillez de contar con un patrón que valide las entradas de texto, es algo que normalmente no valoramos o no le damos importancia. Es mas, leemos opiniones un tanto apresuradas sobre éste editor, del tipo “no lo uses…, es diabolico…, etc” en respuesta  de preguntas de foros, proponiendo alternativas extravagantes. Mi amigo Juan Antonio me hubiera dicho eso de que no lo vuelvas a inventar si ya está inventado. Simplemente úsalo de forma correcta.
 

 Consideración sobre TFormatSettings

Ya hemos visto la estructura de este registro y conocemos que información guarda. El detalle lo podeis encontrar también en la docwiki de Embarcadero si accedeis al siguiente enlace:

http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/SysUtils_TFormatSettings.html

 En la página se nos muestran varias ideas importantes. Que es una estructura de datos que contiene información local que puede ser usada en rutinas de formateo. Que cada miembro de ella es equivalente a una variable global con el mismo nombre. Y finalmente, que esta estructura puede ser usada en sustitución de la generada por el contexto, que puede no ser segura.
 
A menudo recibimos sugerencias de usar estas variables globales que se definen en la unidad SysUtils. como podría ser DecimalSeparator, para cambiar el valor de éste caracter pero como podeis ver por la documentación, estos atributos globales están marcados como deprecated y se desaconseja el uso. En su lugar deberíamos usar los campos de la estructura TFormatSettings. Lo podéis leer en:
 
Su uso es sencillo. Declara una variable del tipo e invoca una función que rellene sus campos de forma que podamos obtener esa información. Hablamos de GetLocaleFormatSettings.
 
 
Esta función recibe como parámetros, un identificador basado sobre el Windows Locale ID y un segundo parametro que va a albergar la referencia a la estructura, de forma que al finalizar la ejecución de la función podemos acceder a nuestro registro y evaluar sus campos de acuerdo a nuestras necesidades: saber que carácter sirve de separación decimal, el separador de los millares, los formatos de fecha, etc…
 
En el ejemplo que veremos a continuación, he invocado la función en la creación del formulario para rellenar la estructura,
GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, fset);
donde LOCALE_SYSTEM_DEFAULT es una constante que nos permite obtener los valores de nuestro sistema, los que tenemos por defecto. Y  fset, una variable de tipo TFormatSettings.  En las paginas de Zarko Gajic también podeis ampliar información sobre la existencia de mas constantes, propias de cada pais, etc…
 

Resumiendo…

Todo lo comentado hasta ahora tendría poco sentido si la estructura no fuera usada ampliamente en muchas de las rutinas de conversión. Siguiendo con el ejemplo que nos ocupa ponemos nuestra vista en la funcion TryStrToFloat
sobrecargada para que pueda ser usada con varios parámetros de tipo distintos y según distintas necesidades. Devuelve True si la conversión se efectuó con éxito y false si no lo tuvo. Y en el parámetro de salida (out) encontramos el valor, resultado de ese proceso de conversión de la cadena.
 
function TryStrToFloat(const S: string; out Value: Extended): Boolean; overload;
function TryStrToFloat(const S: string; out Value: Extended; const FormatSettings: TFormatSettings): Boolean; overload;
function TryStrToFloat(const S: string; out Value: Double): Boolean; overload;
function TryStrToFloat(const S: string; out Value: Double; const FormatSettings: TFormatSettings): Boolean; overload;
function TryStrToFloat(const S: string; out Value: Single): Boolean; overload;
function TryStrToFloat(const S: string; out Value: Single; const FormatSettings: TFormatSettings): Boolean; overload;
 
Existe una versión que considera el uso de la estructura y otra que usa los valores por defecto del sistema, en cada uno de los pares.
 
Estuve pensando durante estos días cómo preparar un pequeño ejemplo que permitiera ver claramente todos estos comentarios que hemos compartido. En las lineas inferiores podeis descargar el pequeño ejemplo que ilustra el tema. El interfaz os muestra  dos componentes TMaskEdit con mascaras que tienen invertido el punto decimal. En la parte superior se nos indica los valores actuales del sistema.
 
Y el selector que aparece a la derecha del formulario, nos permite seleccionar cual separador decimal vamos a usar.
 
Así pues, la acción asociada a los botones convertir fallarán o tendrán éxito en la medida en que la máscara se aplica correctamente sobre la estructura y coincide con la selección. El código es muy sencillo y lo podeis extrapolar a cualquier otra referencia de la estructuras: formatos de fechas, etx… Tanto si enfocamos el problema desde el punto de vista de la edición como de la visualización del formato, puesto que las rutinas de conversión a formato cadena también van a admitirnos el uso de la estructura de información TFormatSettings.
 
El ejemplo se ha compilado con Delphi 2010.
 
Ejemplo
unit UTestMascara;

interface

uses
  Windows, StdCtrls, Controls, Mask, Classes, Forms, Sysutils, ExtCtrls;

type
  TTestMascara = class(TForm)
    mskEd1: TMaskEdit;
    mskEd2: TMaskEdit;
    bnConvertir1: TButton;
    bnConvertir2: TButton;
    lbValor: TLabel;
    lbDisplay: TLabel;
    rgpSelector: TRadioGroup;
    lbMascara1: TLabel;
    lbMascara2: TLabel;
    Label1: TLabel;
    Label2: TLabel;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure bnConvertir1Click(Sender: TObject);
    procedure bnConvertir2Click(Sender: TObject);
    procedure rgpSelectorClick(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    fset: TFormatSettings;
  public
    { Public declarations }
  end;

var
  TestMascara: TTestMascara;

implementation

{$R *.dfm}

procedure TTestMascara.bnConvertir1Click(Sender: TObject);
var
  f: Double;
  s: String;
begin
  f := 0.0;
  s := mskEd1.Text;

  if TryStrToFloat(s, f, fset) then
    lbDisplay.Caption := Format('Correcta la mascara1: %n ', [f])
  else
    lbDisplay.Caption := 'Genera una excepción la máscara 1';
end;

procedure TTestMascara.bnConvertir2Click(Sender: TObject);
var
  f: Double;
  s: String;
begin
  f := 0.0;
  s := mskEd2.Text;

  if TryStrToFloat(s, f, fset) then
    lbDisplay.Caption := Format('Correcta la mascara2: %n ', [f])
  else
    lbDisplay.Caption := 'Genera una excepción la máscara 2';
end;

procedure TTestMascara.Button1Click(Sender: TObject);
begin
  Close;
end;

procedure TTestMascara.FormCreate(Sender: TObject);
const
  KInfo = 'El valor local de %n, usa [%s] para separar miles' +
    'y [%s] en el punto decimal';
var
  f: Double;
  sepmil, sepdec: Char;
begin
  GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, fset);

  sepmil := fset.ThousandSeparator;
  sepdec := fset.DecimalSeparator;

  case sepdec of
    ',': rgpSelector.ItemIndex := 0;
    '.': rgpSelector.ItemIndex := 1;
  else
    rgpSelector.ItemIndex := -1;
  end;

  // elegimos un numero cualquiera para hacer el test
  f := 1234.56;

  lbValor.Caption := Format(KInfo, [f, sepmil, sepdec]);
end;

procedure TTestMascara.rgpSelectorClick(Sender: TObject);
begin
  case rgpSelector.ItemIndex of
    { , } 0: fset.DecimalSeparator := ',';
    { . } 1: fset.DecimalSeparator := '.';
  end;
end;

end.
 
Descargar código fuente

 

Concluimos

Quedaron en el tintero algunos interrogantes pero son menores en mi opinión. No me gustaria finalizar sin hacer mención a uno de ellos, que es el separador de millares y que su presencia harían que fallaran las rutinas de conversión, dado que no pueden ser usados en funciones como TryStrToFloat( ) o similares. Lo podeis leer en la misma documentación:

http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/SysUtils_TryStrToFloat@string@Double.html

 Thousand separators and currency symbols are not allowed in the string. If S doesn’t contain a valid value, TryStrToFloat returns Default.  

Por lo que puestos a usar esa máscara, previamente a la conversión deberíamos extraer y eliminar el/los carácteres no válidos, de forma que no se genere la excepción. Esta representación numérica podría contener varios separadores de milllares, por lo que, suponiendo que fuera el punto decimal los sustituimos todos por una cadena vacía. Yo he usado aqui StringReplace pero hay algunas más disponibles.

StringReplace(MaskEdit1.Text, ‘.’, ”, [rfReplaceAll]);

Nos despedimos aquí. Espero que este taller práctico sea de vuestro agrado y os invito a que participéis activamente en nuestra comunidad y sumemos en el empeño de que sea mas útil y solidaria cada día.

 

 

Embarcadero (Videos del webinar de 1 de Marzo)

marzo 8, 2012 en Entrada Diario, Eventos, Presentaciones, Seminario web, Videos

Diseñe aplicaciones web para móviles y aplicaciones nativas para iOS, Android y más con RAD Studio XE2


Webinar gratuito dirigido por Embarcadero y celebrado el 1 de Marzo de 2012

Os enlazo los tres vídeos que ha hecho públicos Embarcadero sobre el contenido del seminario.

Parte 1: Desarrollando para iOS con Delphi XE2 y FireMonkey

Parte 2: DataSnap Connectors para dispositivos móviles en Delphi XE2

Parte 3: Optimización de interfaces web para dispositivos móviles con RadPHP XE2

 

Existe también en Embarcadero a vuestra disposición (además de éstos publicados en YouTube) según se indica en la información que han compartido la posibilidad de que pueden descargarse desde la web, si alguien lo prefiere.

Fue un webinar muy interesante que os recomiendo sin duda.

¡No os lo perdáis si no pudisteis asistir!.

 

 

Recordatorio encuentro programadores delphi en Barcelona y Madrid

marzo 7, 2012 en Comunidad, Consejo, Entrada Diario, Eventos, Ofertas, Presentaciones, Promociones, XE2

Tal y como hice en los eventos on-line, escribo estas lineas como recordatorio de que en el día de mañana 8 de Marzo (Barcelona) y 9 de Marzo (Madrid), se celebrarán los eventos “ENCUENTRO USUARIOS DELPHI”, organizado por Danysoft.

ENCUENTRO USUARIOS DELPHI

Agenda del evento

09:50 | Bienvenida

10:00 | FireMonkey | Mejorando la Interfaz
La plataforma FireMonkey nos permite crear interfaces de usuario sorprendentes por sus capacidades gráficas. FireMonkey proporciona una plataforma para desplegar aplicaciones nativas en Windows 32 y 64 bits, Mac OS X, iPhone e iPad.
En esta sesión veremos cómo diseñar la interfaz e incorporarla en tus aplicaciones empresariales, dotándolas de una imagen moderna y funcional.

11:15 | VCL Styles y Aplicaciones Web | Moderniza tus aplicaciones
Las VCL Styles nos facilitan un sencillo camino para modernizar y mejorar el aspecto de las aplicaciones sin mucho esfuerzo, por medio de la aplicación de estilos.
Además repasaremos lo que hay que tener en cuenta a la hora de crear o migrar aplicaciones para la Web, centrándonos en cómo interactuar con datos de forma sencilla.

12:00 | Café

12:30 | LiveBindings | Mejora la conexión a bases de datos 
En esta sesión veremos cómo utilizar la tecnología de enlace a datos de LiveBindings, para mejorar la productividad en el desarrollo, permitiéndote la conexión a cualquier fuente de datos, interfaz de usuario o elemento gráfico VCL o FireMonkey.
Además te comentaremos cómo construir dinámicamente los enlaces a datos.

13:15 | DataSnap | Mejora las aplicaciones de bases de datos
DataSnap sigue evolucionando con cada nueva versión, para proporcionarnos todo lo necesario para crear potentes aplicaciones de gestión de bases de datos, cliente-servidor, y con múltiples capas. En esta sesión profundizaremos en su uso, para que conozcas qué hay que tener en cuenta para crear mejores aplicaciones.

14:25 | Preguntas y respuestas

Mas detalle sobre como llegar al lugar del evento consultar en las paginas de Danysoft.

 

Os animo a los que podáis ir a dichos eventos a que asistáis. Son absolutamente recomendables, mas cuando existe y se está haciendo un esfuerzo muy grande en que sean lo mas productivos y útiles posibles para quienes asistan. Se verán los temas principales que afectan a la actual versión, como podéis ver por el contenido de la agenda.

Además, es también una buena oportunidad de conocer algunos compañeros de nuestra comunidad, cosa que siempre sucede durante el transcurso del evento, bien en las paradas de descanso, bien en los momentos finales o iniciales del mismo.

¡Así que ánimo y viento en popa a nuestra comunidad!

 

 

 

 

 

 

Recordatorio próximo seminario web

febrero 13, 2012 en Delphi, Delphi Prism, Entrada Diario, Noticias, Recordatorio, Seminario web, XE2

Os recuerdo: miércoles 15 de febrero se celebrará el seminario web La Base de Datos Integrada, organizado por Embarcadero.

La Base de Datos Integrada

Horario de celebración:

  • California, EE. UU. –  9:00 AM
  • México y Centroamérica –  11:00 AM
  • Colombia–  12:00 PM
  • Argentina – 2:00 PM

Podéis registraros en el siguiente enlace Asistir

El seminario aborda el área de conocimiento de Interbase XE.

Se podrá conocer:
• Lo nuevo en seguridad, escalabilidad y rendimiento de InterBase XE.
• Cómo los fabricantes de software y clientes utilizan InterBase para diseñar, implementar y optimizar sus
aplicaciones.
• Cómo utilizar servicios en la nube con InterBase.
• Cómo aprovechar la sólida integración de InterBase con RAD Studio XE2 y FireMonkey para crear aplicaciones
en múltiples plataformas.
• Desarrollo rápido de aplicaciones de bases de datos multi-capas con InterBase, utilizando DataSnap™.
• Migración de versiones previas de InterBase a XE.

 

El misterio de los 200…

enero 26, 2012 en Advertencia, Artículos, Comunidad, Delphi, Enlace interesante, Entrada Diario, FireMonkey, LiveBindings, XE2

Aunque ya he comentado el contenido de esta entrada en el foro de facebook, necesitaba colgar de algún lado las fuentes que había utilizado para revisar el tema y de paso, dar la oportunidad para quien todavía no forme parte del mismo pueda acceder a su contenido, o por lo menos a las cosas que parecen interesantes. Es por esa razón que he acabado añadiéndola.

En este caso concreto, el hilo de comentarios del foro se originaba cuando uno de los compañeros, siguiendo las indicaciones del código publicado en el blog de Jim Tierney, que forma parte de los blogs de Embarcadero,  se extrañaba de que al intentar llenar los items de un componente TListBox (en tiempo de ejecución) desde una fuente de datos (un clientdataset, el numero de items añadidos al TListBox era como máximo igual o menor a 200. Y eso sucedía aun cuando dicha fuente de datos contuviera una cantidad mayor.

Esta es la entrada en la que me he basado para reproducir el problema y comprenderlo.

LiveBindings: Code to create TBindLink and fill a Listbox

Creo que lo mas interesante de estas lineas no es ya la corrección que se ha hecho para solucionar el problema, que solo ha consistido en añadir la linea de asignación en el procedimiento FillList( ) de la unidad UMain.pas

LBindList.BufferCount:= ARecordCount;

sino en destacar el punto que originaba el problema:

constructor TBindScopeDBEnumerator.Create(ABindScope: TCustomBindScopeDB;
  const AMemberName: string; ABufferCount: Integer);
begin
  FBindScope := ABindScope;
  FMemberName := AMemberName;
  FSaveActiveRecord := FBindScope.FDataLink.ActiveRecord;
  FNextRecord := FSaveActiveRecord;
  if ABufferCount > 0 then
    FBindScope.FDataLink.BufferCount := ABufferCount
  else
    FBindScope.FDataLink.BufferCount := 200;  // default to max 200 records in buffer
end;

 Al final, ese era el motivo por el que, no estando definido el valor del campo BufferCount en TBindList, cualquier movimiento hacia adelante de la estructura del enumerador, comprobaba si habia llegado al ultimo registro por lo que aunque existiera una cantida mayor en el dataset, el enlace le indicaba que había llegado al último.

:-)

En fin… cosas de los valores por defecto que supongo que sería fijado por algún motivo, porque de hecho el comentario en la misma linea corrobora que se hizo por alguna razón que ahora mismo ciertamente no comprendo.

Lo mas gracioso de todo es que pienso que esto debería por la forma en que se ha planteado afectar en tiempo de diseño por lo que quizás deberíamos comprobar que al crear una relación TBindList desde el editor de expresiones, en tiempo de diseño, el valor del campo en cuestión es correcto. Podéis hacer la prueba y comentamos en el foro. Para probarlo, simplemente acceded a la propiedad LiveBindings del TListBox y cread un nuevo enlace de tipo TBindList. Y seguidamente definid para la propiedad Format un nuevo item con los valores indicados en la rutina FillList( ). En las pruebas que he hecho, también se reproduce el error.

Tened en cuenta este punto para no caer en el problema.

 

 

unit UMain;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, Data.DB, Data.Win.ADODB,
  Datasnap.DBClient, FMX.Layouts, FMX.ListBox, FMX.Bind.Editors, Data.Bind.Components,
  Data.Bind.DBScope, Datasnap.Provider, Data.Bind.EngExt, Fmx.Bind.DBEngExt;

type
  TfrmFillListBox = class(TForm)
    lbxData: TListBox;
    bnFill: TButton;
    bnClear: TButton;
    cdsData: TClientDataSet;
    Conexion: TADOConnection;
    qData: TADOTable;
    dsData: TDataSource;
    dspData: TDataSetProvider;
    cdsDataOrderNo: TFloatField;
    cdsDataCustNo: TFloatField;
    BindScopeDB1: TBindScopeDB;
    lbRecordCount: TLabel;
    lbItemsCount: TLabel;
    BindingsList1: TBindingsList;
    procedure bnClearClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure bnFillClick(Sender: TObject);
  private
    { Private declarations }
    procedure FillLabelRecordCount;
    procedure FillLabelItemsCount;
  public
    { Public declarations }
  end;

var
  frmFillListBox: TfrmFillListBox;

implementation

{$R *.fmx}

//fuente del procedimiento: http://blogs.embarcadero.com/jimtierney
//         http://blogs.embarcadero.com/jimtierney/2011/10/03/31601
//
//  El procedimiento encapsula los pasos para rellenar distintos
//  tipos de controles, siguiendo lo que haria el usuario en tiempo de
//  diseño. Es util para el tiempo de ejecución
//
procedure FillList(AControl: TComponent; const AControlExpression: string;
  ASource: TBaseBindScopeComponent; const ASourceExpression: string; ARecordCount: Integer; const ASourceMemberName: string = '');
var
  LBindList: TBindList;
begin
  LBindList := TBindList.Create(nil);
  try
    // Turn off auto properties.
    LBindList.AutoFill := False;
    LBindList.AutoActivate := False;
    LBindList.ControlComponent := AControl;
    LBindList.SourceComponent := ASource;
    LBindList.SourceMemberName := ASourceMemberName;
    LBindList.BufferCount:= ARecordCount; //<- Linea añadida
    with LBindList.FormatExpressions.AddExpression do
    begin
      SourceExpression := ASourceExpression;
      ControlExpression := AControlExpression;
    end;
    LBindList.FillList;
  finally
    LBindList.Free;
  end;
end;

procedure TfrmFillListBox.bnClearClick(Sender: TObject);
begin
  lbxData.Clear;
  FillLabelItemsCount;
  FillLabelRecordCount;
end;

procedure TfrmFillListBox.bnFillClick(Sender: TObject);
begin
  FillList(lbxData, 'Text', BindScopeDB1, 'AsString', dsData.DataSet.RecordCount, 'OrderNo', );
  FillLabelItemsCount;
  FillLabelRecordCount;
end;

procedure TfrmFillListBox.FillLabelItemsCount;
begin
  lbItemsCount.Text:=  'Items.Count: '+IntToStr(lbxData.Items.Count);
end;

procedure TfrmFillListBox.FillLabelRecordCount;
begin
  lbRecordCount.Text:=  'RecordCount: '+IntToStr(cdsData.RecordCount);
end;

procedure TfrmFillListBox.FormCreate(Sender: TObject);

begin
  Conexion.ConnectionString:= 'Provider=Microsoft.Jet.OLEDB.4.0;'+
                              'Data Source=C:Program FilesCommon FilesCodeGear SharedDatadbdemos.mdb;'+
                              'Persist Security Info=False';
  cdsData.Open;

  FillLabelItemsCount;
  FillLabelRecordCount;
end;

end.

Nada mas por comentar. Si deseáis ver el ejemplo podéis acceder al siguiente enlace:

Descargar fuentes

Mi método doble valor y expresiones con LiveBindigns

enero 20, 2012 en Artículos, Delphi, Entrada Diario, LiveBindings, Noticias, Noticias Delphi, Ofertas, XE2

Durante los próximos meses, vamos a ser muchos los compañeros que tomemos contacto con áreas nuevas de nuestro entorno de desarrollo, en esa fase de acercamiento a RadStudio XE2, como pueda ser LiveBindigns, los estilos, las capacidades gráficas 2D/3D. Y es que tenemos por delante, la difícil tarea de asimilar todas estas novedades y comprender de que forma se pueden acoplar a nuestra programación diaria, o del día a día.  Y por lo menos a mí, no me queda duda de que va a ser un proceso largo y evidentemente no trivial. Esa realidad, difícilmente se puede negar o esconder. De hecho, vamos a afrontarla a medida que requiramos funcionalidades más avanzadas y confrontemos la plataforma con las necesidades reales de los proyectos. Es entonces cuando mas echaremos en falta una buena documentación y nos veremos en la necesidad de salir a la red en búsqueda de respuestas. A diferencia de etapas anteriores,  contamos con la dificultad añadida que es la ausencia de documentación o en su defecto, la deficiente calidad de la misma. Y su juventud, que hace dificilmente comparable nuestra VCL con FireMonkey, y que se manifiesta en que todavía no exista ese banco de respuestas que nos permite contrastar si la dificultad ya ha sido enfrentada por otros compañeros.  Esa es la parte mas negativa y creo que ser realista es distinto de ser agorero, actitud en la que muchos van a caer, en ese discurso fácil y destructivo.

Resaltemos también las cosas buenas: En lo positivo, está el hecho reconocido y valorado por muchos compañeros, entre ellos yo, de que Embarcadero conoce esto, es consciente de ello, -el primer paso para solucionarlo- y está haciendo un verdadero esfuerzo por dotar a la nueva plataforma de actualizaciones, que corrijan los errores que van siendo detectados y por supuesto, de nuevos ejemplos que puedan ayudar mitigando o aliviando la falta de documentación.

Estos días anteriores hemos conocido la disponibilidad de la cuarta actualización de RadStudio XE2. ¡La cuarta…! Es una prueba evidente de esa voluntad de hacer las cosas bien, que argumentaba en lineas anteriores. Nosotros siempre preferimos ver el vaso medio lleno antes que medio vacío, por lo que, fuera de la incomoda tarea de las instalaciones y la pereza de hacerlas, prevalece la necesidad de que sean corregidos y mejorados cuantos detalles mejor.

Release Notes for XE2 Update 4

Así que leed con atención las indicaciones de instalación, que son similares a las que pudimos tener en updates anteriores.

Comentaba, siguiendo un poco lo que decía, que van siendo cada vez mas frecuentes las preguntas acerca de estas novedades, pudiendo contar con alguna que otra en el foro de Delphi Solidario.

Hoy por ejemplo, se ha dejado una pregunta en el aire sobre LiveBindings y el componente TListBox, en donde se compartía un problema al llenar la lista interna TStrings que mantiene el componente, para mostrar los distintos items de selección. La persona que hacía la pregunta mostraba que tan solo había conseguido recuperar 200 registros de una tabla que almacenaba una cantidad mayor. Y realmente creo que su problema era no saber si estaba haciendo algo no correcto o era una limitación, cosa improbable aunque difícil de adivinar si no cuentas con una buena documentación o accedes a las fuentes y ves que está sucediendo realmente. Así que tenemos también nosotros, todos los que participamos en la Comunidad, la tarea de aportar toda nuestra ayuda y os invito a volcarnos en nuestros foros y participar de ellos. No me cabe la menor duda que en unos días se resolverá ese problema, ese y los sucesivos, que van a ir apareciendo desde distintos puntos de nuestra Comunidad.

Posiblemente en unos meses también contemos ya con la publicación de los libros que están ahora escribiéndose, el de Marco Cantú (en inglés) o el de Francisco Charte (en español). O se haya añadido mas detalle a la documentación actual, fruto de un nuevo Update. Tengo confianza de que sea como sea, vamos a seguir adelante, mas si prevalece el espíritu que ha marcado siempre a nuestra Comunidad hispana.

Yo, por mi parte, -ya me conocéis- también intento poner mi granito de arena, con independencia de que no siempre podamos resolver los problemas. Siempre acaba uno aprendiendo algo en ese proceso de ayuda y eso es lo verdaderamente importante.

Hace algo mas de una semana compartía con un compañero de ecuador varios correos y me pedía algún enlace al tema de livebindings y el componente TDBLookupCombo. Ya sabéis que la nueva plataforma FireMonkey nos ha dotado de un nuevo sistema de enlace a datos, livebindings, alternativo en la VCL al tradicional uso del [control-datasource-dataset], que ya conocemos. Y mientras todavía nos es factible el uso de ambos sistemas desde la VCL, en los desarrollos ligados a firemonkey solo tenemos disponibles los controles que accedan a datos a través de la nueva tecnología. Quiere decir que ya no existen ni el TDBEdit, ni el TDBLookCombo, etc. y nos valemos de cualquier componente que pueda ser compatible o que acepte el enlace a datos. Y quien dice cualquier, dice eso precisamente…

 Creo que no somos conscientes de la increíble mejora a medio/largo plazo que eso puede suponer. Es un tema de mayor calado que nos puede ayudar en la búsqueda de mejores perspectiva de la Orientación a Objetos.

De mis pesquisas sobre el tema que se me planteaba, pude contrastar algunos detalles que posiblemente podamos compartir mas adelante con algún ejemplo. El hecho es de que el componente TComboBox no se adapta correctamente a lo que podemos demandar de un TDBLookupCombo. No porque no sea capaz de desplegar una lista que lo es, sino porque precisamente le falta lo que le hace distinto: tener una fuente de datos que provea la clave primaria o key value asociada y no el item selector. Esa es la clave del asunto y que dificultaba resolver el problema. El usuario visualiza un item de una lista de alternativas y de ese proceso de selección, lo que guardamos es una clave, cumpliendo las normas habituales de normalización de tablas, de las cuales huelga comentarios.

Os muestro una imagen que compartía con él, en ese intercambio de correo:

Pruebas sobre campos lookup

Había preparado un formulario en el que existían 3 tablas muy básicas. Una con una lista de personas, otra con una lista de grupos y una tercera que se alimentaba de las dos y que las relacionaba, formando equipos de personas asignados a grupos.  Pero bueno… al final, que uno consiga poner un parche y simular el comportamiento del componente no es suficiente ni siempre es correcto. Y realmente, acababa las lineas de mi correo, comentándole que no me gustaba la solución y no la consideraba válida, quedando a la espera de encontrar alguna idea en la red o documentación.

Asumiendo el peligro de equivocarme, creo que ninguno de los enlaces o expresiones existentes, tal y como está ahora mismo, se adaptan al componente TComboBox de forma que se simule el comportamiento de un TDBLookupCombo, por cuanto aunque somos capaces de rellenar la lista de items, cosa que puede hacer el enlace TBindList, al que nos basta indicarle en la propiedad Text del TComboBox, y Value del campo vinculado al origen de datos, produciendo de forma automática que sea relleno cada item de la lista con los valores de la tabla, tropezaremos con el problema que los enlaces o expresiones van a intentar hacer una correspondencia directa entre el item selector y el campo destino. Si optamos en ese camino se mostraran advertencias del tipo: Vd. intenta guardar un string y esperaba un valor entero… ¡Mal camino!.

Otra alternativa, es la de optar por un TBinPosition, para conseguir sincronizar el itemindex del combo con valor actual de la clave guardada en la tabla. Aquí tambien nos encontraremos con un problema. En los ejemplos que usa Embarcadero, que se encuentran  en el directorio Samples/Livebindings (podéis hacer una búsqueda con el término del nombre del proyecto que agrupa los ejemplos: BindSamplesGroup.groupproj) hay uno que se pone en varios foros como muestra de trabajo con TListBox, similar al TComboBox en cuanto a la gestión de cadenas, y siempre se utiliza el enlace TBinPosition para resituar y sincronizar el recno de la tabla con el itemindex… El detalle está en este caso, es que el Recno no se utiliza y no es aplicable a lo que buscamos, porque lo que tiene sentido es el valor de la clave (FieldByName(‘IDGrupo’).AsInteger y no el valor de la propiedad RecNo del registro).   Y el itemindex muestra la posición del item seleccionado pero no existe una correspondencia con lo que nosotros hubieramos identificado con el keyvalue de cada item.

Así que ese camino esta también lleno de problemas y nos obliga a añadir al componente ComboBox varios enlaces a datos, uno para llenar la lista, otro para sincronizar desde el control a la fuente de datos y un tercero para enfocar el sentido contrario, desde la fuente de datos al componente. Todo demasiado complicado, en relación a lo sencillo que es el enlace que hubieramos planteado desde la plataforma VCL.

Pero decía también al principio de la entrada que el hecho ayudar a alguien implica también el constante aprendizaje que uno recibe y que nos hace descubrir cosas o aspectos que en principio no esperabamos. Y digo esto porque el problema realmente no ha estado en la tecnología sino en el aprendizaje de su uso.

El motor de expresiones que se ha incorporado para sostener el corazón de LiveBindings es algo que aun está por descubrir por la Comunidad y que poco a poco va a ir siendo conocido a medida que vayamos teniendo buena documentación y aprendamos como valernos de él, en lugar de luchar contra él.

Alguien pensaría que los métodos que en tiempo de diseño nos muestra el entorno y que podemos utilizar para generar las expresiones va a ser algo inmutable y nada mas lejos de la realidad. Vamos a ver un ejemplo muy sencillo adaptado sobre los que acompañan a la unidad System.Bindings.Methods y que va a permitir que sea calculado el valor doble del introducido en un casilla cualquiera.

 

Mi método Doble Valor

unit UMyMethod;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, System.Bindings.Methods,
  System.Rtti, System.TypInfo, System.Generics.Collections, System.Bindings.Evaluator,
  System.Bindings.ObjEval, System.Bindings.EvalProtocol, System.Bindings.Consts,
  FMX.Edit, Data.Bind.EngExt, Fmx.Bind.DBEngExt, System.Bindings.Outputs,
  Data.Bind.Components, Fmx.Bind.Editors;

resourcestring
  sInvalidValueError = 'Valor no aplicable a la operación';

type
  TfrmDobleValor = class(TForm)
    edValor: TEdit;
    edDobleValor: TEdit;
    lbDobleValor: TLabel;
    lbValor: TLabel;
    BindingsList1: TBindingsList;
    BindExpressionedDobleValor1: TBindExpression;
    Label1: TLabel;
    procedure edValorChange(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmDobleValor: TfrmDobleValor;

implementation

{$R *.fmx}

function MakeMethodDoubleValue: IInvokable;
var
  str: String;
begin
  Result := MakeInvokable(function(Args: TArray): IValue
  var
    v1: IValue;
    LExt: Extended;
  begin
    if Length(Args) <> 1 then
      raise EEvaluatorError.Create(sFormatArgError);
    v1 := Args[0];
    str:= Trim(v1.GetValue.AsString);
    //manejamos el caso de valor vacio
    if v1.GetValue.IsEmpty then
      Exit(TValueWrapper.Create(nil))
    else
    begin
       if TryStrToFloat(str, LExt) then
         Exit(TValueWrapper.Create(LExt * 2))
       else raise EEvaluatorError.Create(sInvalidValueError);
    end;
  end);
end;

const
  sIDDoubleValue = 'DoubleValue';

 
procedure RegisterMyMethod;
begin
  TBindingMethodsFactory.RegisterMethod(
    TMethodDescription.Create(
      MakeMethodDoubleValue,        //AInvokable:IInvokable
      sIDDoubleValue,               //AID
      sIDDoubleValue,               //AName
      '',                           //AUnitName
      True,                         //ADefaultEnabled
      '',                           //ADescription
      nil));                        //AFrameworkClass
end;

procedure UnRegisterMyMethod;
begin
   TBindingMethodsFactory.UnRegisterMethod(sIDDoubleValue);
end;

procedure TfrmDobleValor.edValorChange(Sender: TObject);
begin
 BindingsList1.Notify(edValor, 'Text');
end;

initialization
  RegisterMyMethod;

finalization
  UnRegisterMyMethod;

end.

Descargar fuentes

La moraleja de la historia creo que se adivina: Cuando caía hace un par de días sobre dicha unidad (System.Bindings.Methods), fruto de querer resolver el problema, y podía ver como se habían generado las expresiones del editor, y realmente apreciaba la “facilidad” que existía en crearlas y usarlas, y la potencia que podía aportar, sin tener que depender de la que mostraba el editor, sino crearme las propias expresiones, me hacía también suponer que se abrían alternativas, pudiendo generar adicional mente vías para entiquecer el flujo de datos entre el componente y la fuente, que era precisamente lo que ahora pienso que me impedía resolver el problema. Posiblemente, la expresión que recorre la tabla para llenar la lista pueda adicionalmente rellenar los valores de las claves o keyvalues, por lo que no necesite mas de dos enlaces entre ellos: el que alimenta la lista de cadenas y el que hace corresponder una clave con un valor en la tabla, mostrando el texto selector.

Nada mas por hoy. Un abrazo a todos y estamos de vuelta para pelear por la Comunidad. Si hay algo que nadie puede prohibirme es seguir aprendiendo y disfrutando de ello.

Enlaces sobre el tema imprescindibles:

http://www.jcolibri.com/articles/firemonkey/livebindings_delphi_xe2/livebindings_delphi_xe2.html

http://www.danieleteti.it/2011/08/30/in-the-core-of-livebindings-expressions-of-rad-studio-xe2/

http://neftali.clubdelphi.com/?p=1783

Feliz Navidad :-)

diciembre 24, 2011 en Entrada Diario, Mis cosas

Estimados amigos y compañeros, os deseo una Feliz Navidad y un próspero año. Os deseo de corazón que seáis muy felices y que estas fechas tan entrañables traigan Paz a vuestro corazón.

Ese es un maravilloso regalo. :-)

Como Cristiano,para mi la Navidad es un tiempo muy especial, que nos permite nacer año a año, encontrando nuevas fuerzas para intentar ser luz y sal para el Mundo.

Sed muy felices.

 

Videos demostrativos Firemonkey – Demos (Danysoft)

noviembre 29, 2011 en 64bits, Comunidad, Delphi, Enlace interesante, FireMonkey, Nos deja la semana..., Seminario web, Videos, XE2

 

Con fecha de hoy, Danysoft ha subido a YouTube dos vídeos demostrativos, que sin duda os van a parecer interesantes y es por eso el remarcarlos aquí e incluirlos en esta entrada.

Ambos son parte de la misma sesión: El primero de ellos aborda el tema de Firemonkey desde la perspectiva de Windows, mostrando algunas posibilidades de la plataforma,  como efectos y calidad gráfica propia de los nuevos componentes y del uso de la GPU. El segundo vídeo prosigue la ejecución de la demo en el lado del compilador para Mac, mostrando la ejecución del programa en el simulador de iPhone.

Ya he añadido, igualmente, los enlaces al grupo de Facebook Delphi Solidario, para quienes estáis siguiendo el día a día en él. Gran trabajo el que está haciendo el partner español de Embarcadero, Danysoft, al generar esta colección de recursos que van quedando disponibles para todos nosotros.

Que los disfrutéis.

 

Parte 1.

Rad Studio XE2 | FireMonkey | demo windows

Parte 2.

Rad Studio XE2 | FireMonkey | demo Mac

 

Ultima promoción de Danysoft para RadStudio XE2

noviembre 15, 2011 en 64bits, Delphi, Noticias, Noticias Delphi, Ofertas, Promociones, updates, XE2

Os incluyo en la tabla inferior un detalle de la ultima oferta de Danysoft para RadStudio XE2.

Uno de los aspectos interesantes de la misma, fuera de lo que es el producto en si, es que la oferta permite hasta el 30 de Diciembre y con carácter extraordinario,  actualizarse desde versiones anteriores a Delphi 2007,  desligándose de las condiciones habituales que marcan el fin del derecho de actualizaciones y la obligación de la compra de nueva licencia.

Me ha parecido que se puede resaltar y por ello os incluyo el texto íntegro de la pagina de Danysoft. Para mas información sobre la misma podeis contactar en los enlaces que se detallan.

 

DETALLE DE LA ULTIMA PROMOCIÓN DE DANYSOFT PARA RADSTUDIO XE2

Ver pagina Danysoft: Actualización Delphi, C++Builder, RAD Studio 2006 y versiones anteriores Texto inferior extraído de la oferta existente en dicha páginaimage

 

Fecha oferta: 15/11/2011

 

Actualización Delphi, C++Builder, RAD Studio 2006 y versiones anteriores

Si dispones de Delphi, C++Builder, o RAD Studio 2006 o de una versión anterior, aprovecha esta oportunidad única y actualiza tu software, consiguiendo todas las ventajas de la versión XE2 a un precio increíble. Aprovecha esta oportunidad antes del 30 de diciembre de 2011 solo con Danysoft.


Oportunidad especial para actualizar Delphi, C++Builder, RAD Studio 2006 y versiones anteriores

Si eres usuario registrado de Delphi, C++ Builder, Borland Developer Studio 2006, o de una versión anterior, ahora tienes otra oportunidad para conseguir la nueva versión XE2 con un descuento de hasta el 45% respecto al precio del producto nuevo, pero solo hasta el 30 de Diciembre de 2011.

Además de este descuento, al realizar ahora la compra, también disfrutarás de una promoción especial y obtendrás FastCube, Rapid SQL y más herramientas de análisis de forma totalmente gratuita (valoradas en 2935€), dependiendo de la actualización escogidaclick aquí para más información.

La versión XE2 de estos productos es la más avanzada hasta el momento, los desarrolladores reconocen las nuevas capacidades de la versión XE2, la nueva versión de 64-bits desarrollada para Windows. Además el mismo código fuente es utilizado tanto para Windows como para Mac en Delphi y C++. También se están consiguiendo nuevos desarrollos para móviles en iOS y Android con RadPHP(parte de RAD Studio XE2).

Si eres usuario de Delphi o C++ Builder, tu puedes actualizar a la versión XE2 de tu herramienta o conseguir RAD Studio. Si tu eres usuario de Borland Developer Studio, puedes actualizar a RAD Studio XE2 el cual incluye la nueva versión XE2 de Delphi, C++Builder, Embarcadero Prism para .NET y RadPHP para web y dispositivos moviles. También puedes cambiar el tipo de tu edición, por ejemplo con tu versión profesional, puedes actualizar tanto a profesional como a enterprise de XE2.

Si observas algunas de las posibilidades que ofrecemos de actualización, podrás ver que es solo para versiones 2007 en adelante, pero no te preocupes gracias a esta promoción podrás conseguir cualquier actualización desde cualquier versión, pero solo antes del 30 de Diciembre de 2011. Por ello no dejes pasar esta oportunidad, ya que a partir de 2012 para conseguir la versión de XE2 o futuras versiones tendrás que adquirirlo como producto nuevo.

XE2

Productos que puedes actualizar

Usuarios de las versiones 2006 o anteriores que hayan comprado cualquiera de los productos:

• Delphi
• C++Builder
• Borland Developer Studio
• Delphi for .NET
• C#Builder
• Kylix
• Turbo Delphi Professional
• Turbo C++ Professional

Todas las actualizaciones regulares de Delphi XE2, C + + Builder XE2 y RAD Studio XE2 están disponibles para versiones 2007 y posteriores. La actualización de “Starter” SKUs no está incluida. Esta promoción es solo para Delphi, C + + Builder y RAD Studio. Contacta con Danysoft para más información.

Más información condiciones actualización

Adquirir Actualización Delphi, C++Builder, RAD Studio