Mostrando entradas con la etiqueta TDBGrid. Mostrar todas las entradas
Mostrando entradas con la etiqueta TDBGrid. Mostrar todas las entradas

miércoles, 23 de octubre de 2019

Editor simple de SQLite.

Son tan solo 200 líneas de código y desde ya, la librería de SQLite. Desde ya hay programas potentes y también portables como SQLite Studio, el cual uso y recomiendo. Volviendo al editor simple, lo hice para un uso muy específico y limitado, conecta a la base de datos que le indiquemos, muestra las tablas, permite ejecutar consultar cuyo resultado se muestra en un TDBGrid el cual cuenta con un par de opciones y ejecutar sentencias de actualizaciones que realiza mediante TZConnection.ExecuteDirect.
También tiene una opción para leer de un archivo un script SQL y luego ejecutarlo.
Creo que puede ser útil para quienes comiencen con SQLite, Lazarus y ZeosLib.


El código: descargar

unit principal;

{$mode objfpc}{$H+}

interface

uses
Classes, SysUtils, db, FileUtil, Forms, Controls, Graphics, Dialogs,
StdCtrls, Buttons, DBGrids, DbCtrls, ZConnection, ZDataset;

type
  TConexion=(Conectado, NoConectado);

type

{ TForm1 }

TForm1 = class(TForm)
  BBorrarMemo: TBitBtn;
  BCerrarConsulta: TBitBtn;
  btnSelBD: TBitBtn;
  btnConectar: TBitBtn;
  BCerrar: TBitBtn;
  btnDesconectar: TBitBtn;
  BExecute: TBitBtn;
  BConsulta: TBitBtn;
  btnLeerArchivo: TBitBtn;
  cbAutoCommit: TCheckBox;
  cbAutoSizeCol: TCheckBox;
  DataSource1: TDataSource;
  DBGrid1: TDBGrid;
  DBNavigator1: TDBNavigator;
  edBaseDeDatos: TEdit;
  edConexion: TEdit;
  Label1: TLabel;
  lbTablas: TListBox;
  Memo1: TMemo;
  OpenDialog1: TOpenDialog;
  ZConnection1: TZConnection;
  ZQuery1: TZQuery;
  procedure BBorrarMemoClick(Sender: TObject);
  procedure BCerrarConsultaClick(Sender: TObject);
  procedure BConsultaClick(Sender: TObject);
  procedure BExecuteClick(Sender: TObject);
  procedure btnLeerArchivoClick(Sender: TObject);
  procedure btnSelBDClick(Sender: TObject);
  procedure btnConectarClick(Sender: TObject);
  procedure BCerrarClick(Sender: TObject);
  procedure btnDesconectarClick(Sender: TObject);
  procedure cbAutoSizeColChange(Sender: TObject);
  procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
  procedure FormCreate(Sender: TObject);
  procedure lbTablasDblClick(Sender: TObject);
private
  Conexion:TConexion;
  procedure MuestroTablas;
  function HayConexion:Boolean;
{ private declarations }
public
{ public declarations }
end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
  Conexion:=NoConectado;
end;

procedure TForm1.btnSelBDClick(Sender: TObject);
begin
  if OpenDialog1.Execute then edBaseDeDatos.Text:= OpenDialog1.FileName;
end;

procedure TForm1.btnLeerArchivoClick(Sender: TObject);
begin
 if OpenDialog1.Execute then Memo1.Lines.LoadFromFile(OpenDialog1.FileName);
end;

procedure TForm1.BBorrarMemoClick(Sender: TObject);
begin
  Memo1.Clear;
end;

procedure TForm1.BCerrarConsultaClick(Sender: TObject);
begin
  ZQuery1.Close;
end;

procedure TForm1.BConsultaClick(Sender: TObject);
begin
  if not(HayConexion) then Exit;
  ZQuery1.Close;
  ZQuery1.SQL.Text:=Memo1.Text;
  ZQuery1.Open;
end;

procedure TForm1.BExecuteClick(Sender: TObject);
var
  n:Integer;
begin
  if not(HayConexion) then Exit;
  if ZConnection1.ExecuteDirect(Memo1.Text, n) then Memo1.Lines.Add('OK! '+IntToStr(n)+'      filas.');
end;

procedure TForm1.btnConectarClick(Sender: TObject);
begin
  if Conexion=Conectado then
  begin
    ShowMessage('Hay una conexión establecida, primero desconecte dicha conexión.');
    Exit;
  end;
  if not (FileExists(edBaseDeDatos.Text)) then exit;
  ZConnection1.Database:=edBaseDeDatos.Text;
  if not(cbAutoCommit.Checked) then ZConnection1.AutoCommit:=False;
  ZConnection1.Connect;
  if ZConnection1.Connected then
  begin
    edConexion.Text:='Conectado';
    edConexion.Font.Color:=clGreen;
    Conexion:=Conectado;
    MuestroTablas;
  end;
end;

procedure TForm1.BCerrarClick(Sender: TObject);
begin
  Close;
end;

procedure TForm1.btnDesconectarClick(Sender: TObject);
begin
  ZConnection1.Disconnect;
  edConexion.Text:='Desconectado';
  edConexion.Font.Color:=clRed;
  Conexion:=NoConectado;
  lbTablas.Clear;
end;

procedure TForm1.cbAutoSizeColChange(Sender: TObject);
begin
  if cbAutoSizeCol.Checked then DBGrid1.AutoFillColumns:=False else DBGrid1.AutoFillColumns:=True;
end;

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  ZConnection1.Disconnect;
  CloseAction:=caFree;
end;

procedure TForm1.lbTablasDblClick(Sender: TObject);
begin
  if not(HayConexion) then Exit;
  Memo1.Clear;
  Memo1.Lines.Add('SELECT * FROM '+lbTablas.Items[lbTablas.ItemIndex]+';');
  ZQuery1.Close;
  ZQuery1.SQL.Text:=Memo1.Text;
  ZQuery1.Open;
end;

procedure TForm1.MuestroTablas;
var
  ZQTablas:TZQuery;
begin
  lbTablas.Clear;
  ZQTablas:=TZQuery.Create(nil);
  ZQTablas.Connection:=ZConnection1;
  ZQTablas.SQL.Text:='SELECT name FROM sqlite_master WHERE type='+
  QuotedStr('table')+' and name <>'+QuotedStr('sqlite_sequence');
  ZQTablas.Open;
  if ZQTablas.RecordCount <1 then Exit;
  ZQTablas.First;
  while not(ZQTablas.EOF) do
  begin
    lbTablas.AddItem(ZQTablas.FieldByName('name').AsString,lbTablas);
    ZQTablas.Next;
  end;
  ZQTablas.Close;
  FreeAndNil(ZQTablas);
end;

function TForm1.HayConexion: Boolean;
begin
  if not(ZConnection1.Connected) then
  begin
    Memo1.Lines.Add('No hay establecida ninguna conexión.');
    Exit(False);
  end;
  Result:=True;
end;

end.


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.










domingo, 17 de junio de 2018

TDBGrid: ordenar por columnas.

Ordenar los datos de una consulta SQL mostrados en un DBGrid al hacer click en la columna. En este caso además de ordenar, pondremos en bold (negrita) el título de la columna que está ordenada. (Para algo más avanzado aquí)

En el inspector de objetos, en DBGrid, eventos, buscar: OnTitleClick


y generar el evento (procedimiento):

procedure TFdCtas.DBGridCtasTitleClick(Column: TColumn);
var
  i:Integer;
begin
  for i:=0 to DBGridCtas.Columns.Count-1 do DBGridCtas.Columns.Items[i].Title.Font.Style:=[];
  ZQCtas.Close;
  ZQCtas.SQL.Text:='SELECT * FROM dcuentas ORDER BY '+Column.FieldName+';';
  ZQCtas.Open;
  Column.Title.Font.Style:=[fsBold];
end;


En el ciclo for quitamos "Bold" de todas las columnas y al final del código lo establecemos para la actual (que viene como parámetro).

Quedando así:



sábado, 27 de enero de 2018

DBGrid: Anchors de las columnas

Si bien TDBGrid tiene la propiedad Anchors (Anclajes), cuando la definimos y agrandamos y achicamos el formulario, la grilla también lo hace, mas no sus columnas, la cuales carecen de la propiedad Anchors, entonces el ancho de las columnas permanece estático, no cambia.

¿Cómo hacer que las columnas cambien el ancho cuando se agranda el formulario que contiene la DBGrid?

Creando el evento FormResize y asignarlo a los eventos del Form OnResize y OnChangeBounds. Desde ya el grid debe estar anclado al formulario y tener definido al menos las constraints de valores mínimos. Luego, un poco de matemáticas y eso es todo.


Así tengo definido el anclaje del DBGrid, mucho no entiendo de este tema, mucho prueba y error hasta dar con el resultado que busco.


Las Constraints del DBGrid, aunque esto es relativo si están definidas las del Form.


En los eventos del DBGrid, desde el inspector de objetos, creamos el evento para OnResize y también lo asignamos a OnChangeBounds.

procedure TfrmBancos.FormResize(Sender: TObject);
var
  ndiv, nmod, ndist:Integer;
begin
  ndist:=(Width-Constraints.MinWidth);
  if ndist < 4 then exit;
  ndiv:=ndist div 4;
  nmod:=ndist mod 4;
  DBGrid1.Columns.Items[1].Width:=160+ndiv;
  DBGrid1.Columns.Items[2].Width:=120+ndiv;
  DBGrid1.Columns.Items[3].Width:=150+ndiv;
  DBGrid1.Columns.Items[4].Width:=160+ndiv;
  if nmod>0 then
    DBGrid1.Columns.Items[4].Width:=DBGrid1.Columns.Items[4].Width+nmod;
end;


En este caso, la columna 0 (cero) no la muestro, solo las 1,2,3 y 4 con un ancho definido en la propiedad width de cada columna de 160, 120, 150 y 160 respectivamente.
Lo que hago es calcular en cuántos píxeles se agranda el formulario y en base a ello, lo distribuyo en las columnas, como son 4, hago la división entera sobre 4 y el resto (mod) lógicamente también sobre 4. Luego elijo a que columna se asigno el sobrante si es que lo hay (mod 4).

miércoles, 6 de septiembre de 2017

DBGrid: Formato de la columna según el tipo de campo

En tiempo de diseño y conociendo la tabla es una cosa, pero en tiempo de ejecución y sin saber nada de la tabla, ya es distinto. Para empezar nos encontramos con tipos de datos enumerados y por ende, debemos conocerlos. Luego hay que recorrer las columnas o campos y definir el formato según lo que necesitemos, siendo lo normal los tipos de dato numéricos y de fecha. Para el ejemplo se recorrerán las columnas de una tabla SQL y se cambiará el formato del DBGird si el campo es numérico decimal.

procedure TForm1.FormatoColumnasGrid;
var
  ind:Integer;
begin
  FormatSettings.DecimalSeparator:='.';
  for ind:=0 to ZQ.FieldCount-1 do
    if (ZQ.FieldDefs.Items[ind].DataType=ftFloat) or (ZQ.FieldDefs.Items[ind].DataType=ftCurrency)
    or (ZQ.FieldDefs.Items[ind].DataType=ftBCD) then
      DBGrid1.Columns[ind].DisplayFormat:='#0.00';
end;


Este procedimiento se llama luego de habilitarse el DBGrid. Se establece el separador decimal para establecer correctamente el formato aunque también se podría hacer de forma automática o preguntarle al usuario.

Se utiliza FieldCount – 1 porque la indexación del ZQuery (de ZeosLib) comienza por cero. DataType es del tipo enumerado, para SQL los valores de numéricos con decimales son: ftFloat, ftCurrency y ftBCD,

Listado de tipos de datos completo en español 

Documentación de TFieldType

DBGrid: seleccionar una columna

El componente DBGrid carece de una opción para marcar una columna de la forma en que lo hacemos con una fila con dgRowSelect, es decir, no tenemos la opción dgColSelect. Lo cual no significa que no podamos hacerlo, de hecho el código es bastante simple:

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
begin
  DBGrid1.Columns[Column.Index].Color := clHighlight;
  DBGrid1.Columns[column.Index].Title.Color := clHighlight;
end;


Basta con dos líneas de código para el evento TitleClick que nos envía parámetro Column del tipo TColumn, esto nos facilita todo, pues usamos la propiedad Index para saber sobre que columna (el itulo  de la columna) se hizo el click y le cambiamos el color tanto al título como a las celdas, según se desee.

lunes, 4 de septiembre de 2017

Conectar SQLite y editar una tabla

En este video vemos como hacer un ABM de una tabla en 2 minutos sin escribir código. Desde ya un ABM es mucho más que lo que se muestra, pero que sirva como punto de partida. Ver en pantalla completa.



La conexión se realiza mediante Zconnection, componente del paquete Zeos Lib, ZQuery y un DataSource.

Soltamos los 3 componentes en el Form, indicamos la base de datos en ZConnection1 y el protocolo sqlite-3, conectamos. No es necesario nada más como se puede ver.

ZQuery1: indicamos que se conecta via ZConnection1, escribimos la consulta en SQL. Antes de activar, vamos a DataSource1 y le indicamos que el DataSet vendrá de ZQuery1. Activamos ZQuery1.

Agreamos un DBGrid y le indicamos que el DataSource será DataSource1.

Agregamos un DBNavigator y de igual forma que con el DBGrid le establecemos el DataSource1.

Por ningún motivo usar ZTable nunca, no tiene sentido y creo que no eliminan el componente por razones de compatibilidad con versiones anteriores.

Todo esto se puede hacer en tiempo de ejecución, escribiendo el código, que no es mucho por cierto y es lo más normal cuando se está desarrollando un programa y no un ejemplo. También se utilizan Data Modules para soltar ahí todos los componentes no visuales y trabajar más cómodo.