viernes, 17 de agosto de 2018

TMemo: evitar el enter.

Si bien una de sus propiedades es WantReturns y le podemos asignar False para evitar la línea nueva, a veces no funciona, al menos con la versión 1.6 de Lazarus y 3.0 de FreePascal usando el widget Gtk-2.
No obstante la solución es muy simple utilizando el evento OnKeyPress de TMemo:

procedure TForm1.mmDetalleKeyPress(Sender: TObject; var Key: char);
begin
  if (Key in [#13,#10]) then Key:=#0;
end;


mmDetalle es la variable del tipo TMemo.
Si la tecla presionada es Enter se anula.

TEdit: rellenar con ceros u otro caracter.

La función AddChar incluida en la unidad StrUtils hace esto.

function AddChar(C: Char; const S: string; N: Integer): string; 

El primer parámetro es el caracter con el cual vamos a rellenar los espacios del string, el segundo parámetro es el string a rellenar y el tercero la cantidad de lugares a rellenar (lo normal es que sea la misma cantidad de caracteres del string).

Ejemplo: un TEdit para que el usuario ingrese el número de un comprobante y al abandonar el TEdit, el mismo complete con ceros a la izquierda. Nos valemos del método OnExit del TEdit:

procedure TForm1.edNroExit(Sender: TObject);
begin
  edNro.Text:=AddChar('0',edNro.Text,8);
end;


El edNro es la variable del tipo TEdit y la propiedad MaxLength es 8, el resto de las propiedades son las predefinidas por el IDE Lazarus.
En lugar de pasar el número 8 se podría pasar la propiedad edNro.MaxLength.

jueves, 16 de agosto de 2018

TDBLookupComboBox: Validar.

Validar un combo del tipo TDBLookupComboBox con las siguientes propiedades:

Style: cdDropDown
ArrowKeysTravers: True
AutoComplete: True

Es una configuración muy cómoda para el usuario, pero permite que deje el valor del combo en blanco o con un valor que no coincide con ningún elemento, por el motivo que sea (distracción o "a ver que pasa").
Nota: para combos con pocos elementos conviene utilizar el estilo (style) csDropDownList y deshabilitar la propiedad de autocompletado.
Volviendo al tema de inicio, la validación se realiza a través del evento OnExit:

procedure TFCRegCompras.cmbProvExit(Sender: TObject);
begin
  if cmbProv.KeyValue=Null then
  begin
    ShowMessage('Seleccione un proveedor.');
    cmbProv.SetFocus;
  end;

end;

Desde ya es muy conveniente antes de cargar y habilitar el combo, verificar que el dataset no esté vacío, si esto sucediese, el programa no se colgaría, pero una vez que el usuario entra al combo, no podría salir nunca porque KeyValue siempre sería Null y al utilizar SetFocus vuelve a entrar al combo. Es una validación muy útil pero deben tomarse ciertas precauciones. Por ejemplo, en un programa de registración de compras, donde otros combos y valores dependen del proveedor seleccionado, usando el evento OnChange del combo de proveedores, es fundamental tomar este tipo de medidas.

lunes, 13 de agosto de 2018

TDBGrid: ordenar por columnas ASC y DESC con flechas.



Anteriormente escribí acerca de ordenar las columnas de un DBGrid de forma simple y en un solo sentido. Ahora veremos como hacerlo de forma tal que además de poner en negrita el título de la columna que posee el orden, le agregue una flecha ascendente (arriba) o una descendente (abajo) y que si el usuario hace click en el título de una columna y la misma es la que está ordenando la grilla, entonces cambie el orden de la misma, es decir, si está ordenada ascendentemente pasará a ordenarse en sentido descendente.

Para las flechas necesitamos un TImageList.


Este componente se encuentra en la paleta Common Controls (el último que se ve en la imagen).


Desde el inspector de objetos estableceremos las propiedades Height (alto) y Width (ancho) de ImageList1 en 16 pixeles. Luego cargamos las imágenes de las flechas en dicho componente.

Éstas son las flechas utilizadas:


Ahora debemos conectar la lista de imágenes con la grilla.


Seleccionamos el DBGrid en el inspector de objetos y en TitleImageList asignamos ImageList1. Luego en "Eventos" creamos el procedimiento para OnTitleClick:

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
var
  i:Integer;
  AscDes:String;
begin
  if Column.Title.ImageIndex=0 then AscDes:=' DESC ' else AscDes:=' ASC ';
  for i:=0 to DBGrid1.Columns.Count-1 do
  begin
    DBGrid1.Columns.Items[i].Title.Font.Style:=[];
    DBGrid1.Columns.Items[i].Title.ImageIndex:=-1;
  end;
  ZQuery1.Close;
  sqlOrder:=' ORDER BY '+Column.FieldName+AscDes+';';
  sqlgrid:=sqlSelect+sqlWhere+sqlOrder;
  ZQuery1.SQL.Text:=sqlgrid;
  ZQuery1.Open;
  Column.Title.Font.Style:=[fsBold];
  if AscDes=' DESC ' then Column.Title.ImageIndex:=1 else Column.Title.ImageIndex:=0;
end;


Las variables sqlOrder, sqlGrid, sqlSelect y sqlWhere las defino como privadas para la clase del formulario, son del tipo string y su utilización es más que obvia, permitiendo por ejemplo, ordenar manteniendo un filtro definido por el usuario (sqlWhere).
Atención a no confundir Column con Columns, la primera viene como parámetro, es la columna en la cual el usuario hizo click. En cambio Column"s" es miembro de TDBgrid.
Lo primero que hacemos es averiguar si la columna (variable Column del tipo TColumn) está ordenada de manera descendente, caso contrario la damos como ascendente y establecemos el valor correspondiente a la variable local AscDes que luego utilizaremos en la consulta SQL.
Lo siguiente es recorrer las columnas (Columns) del grid y quitarles el [bold] y la flecha.
Cerramos el Query, armamos el string de la consulta y reabrimos la misma.
Finalmente marcamos en negrita el título de la columna y se asignamos la imagen de la flecha que le corresponde.