03 abril 2009

Crea tu propio editor de informes (IV)

En el artículo de hoy voy a añadir al editor la funcionalidad de añadir conectarse a una base de datos Interbase/Firebird para añadir los campos de las tablas.

AÑADIENDO MÁS COMPONENTES AL INFORME

Para poder conectar con la base de datos necesitamos añadir tres componentes al formulario FInforme:

1º Un componente TIBDatabase que se encuentra en la sección Interbase y que vamos a llamar BaseDatos:


Modificamos su propiedad LoginPrompt a False y no hay que olvidarse de darle el usuario SYSDBA y la contraseña masterkey al hacer doble clic sobre el mismo.

2º Un componente TIBTransaction que también se encuentra en Interbase y le ponemos el nombre Transaccion:


También debemos vincular la transacción a la base de datos mediante la propiedad DefaultTransaction.

3º Y un componente de la clase TIBTable para traernos los campos de la tabla al hacer la vista previa.

CREANDO EL FORMULARIO DE CONFIGURACION

Creamos un nuevo formulario llamado FConfiguracion con lo siguiente:


Es un formulario de tipo diálogo que contiene una etiqueta, un componente TEdit llamado Ruta y un botón llamado BExaminar que al pulsarlo utiliza al componente TOpenDialog para elegir una base de datos local:

procedure TFConfiguracion.BExaminarClick(Sender: TObject);
begin
Abrir.Filter := 'Interbase/Firebird|*.gdb;*.fdb';

if Abrir.Execute then
Ruta.Text := Abrir.FileName;
end;

Si la base de datos fuera remota el botón Examinar no sirve de nada ya que la ruta sería una unidad real del servidor.

Para poder realizar un test de la conexión lo que hacemos es pasarle a este formulario la base de datos con la que vamos a conectar. Para ello creamos esta variable pública:

public
{ Public declarations }
BaseDatos: TIBDatabase;

Para poder compilar este componente debemos añadir a la sección uses la unidad IBDatabase. Entonces en el botón de comprobar la conexión hacemos esto:

procedure TFConfiguracion.BConectarClick(Sender: TObject);
begin
if BaseDatos.Connected then
BaseDatos.Close;

BaseDatos.DatabaseName := IP.Text + ':' + Ruta.Text;

try
BaseDatos.Open;
except
raise;
end;

Application.MessageBox( 'Conexión realizada correctamente.',
'Conectado', MB_ICONINFORMATION );
end;

Ahora nos vamos al formulario FInforme y añadimos una nueva opción al menú contextual:


Al pinchar sobre esta opción abrimos el formulario de configuración:

procedure TFInforme.ConfiguracionClick(Sender: TObject);
begin
Application.CreateForm( TFConfiguracion, FConfiguracion );
FConfiguracion.BaseDatos := BaseDatos;
FConfiguracion.ShowModal;
end;

Una vez conectados a la base de datos ya podemos crear añadir campos de bases de datos TQRDBText.

AÑADIENDO LOS COMPONENTES TDBTEXT

Aquí no voy a enrollarme mucho ya que el modo insertar los campos TQRDBText va a ser el mismo que he utilizado para los componentes TQRLabel o TQRShape.

Lo primero que he hecho es añadir la opción Campo a nuestro menú contextual:


Cuya implementación es la siguiente:

procedure TFInforme.CampoClick(Sender: TObject);
begin
if BandaActual = nil then
begin
Application.MessageBox( 'Debe crear una banda.',
'Acceso denegado', MB_ICONSTOP );
Exit;
end;

QuitarSeleccionados;
with TQRDBText.Create(BandaActual) do
begin
Parent := BandaActual;
Left := 10;
Top := 10;
Inc(UltimoID);
Tag := UltimoID;
Caption := 'Campo' + IntToStr(UltimoID);
Name := Caption;
end;
end;

Después he modificado el procedimiento SeleccionarComponente:

procedure TFInforme.SeleccionarComponente;

...

// ¿Ha pinchado una etiqueta, una figura o un campo?
if (Seleccionado is TQRLabel) or (Seleccionado is TQRShape) or
(Seleccionado is TQRDBText) then

...


Luego he modificado el procedimiento MoverRatonPulsado:

procedure TFInforme.MoverRatonPulsado;

...

// ¿Estamos moviendo una etiqueta, una figura o un campo?
if (Seleccionado is TQRLabel) or (Seleccionado is TQRShape) or
(Seleccionado is TQRDBText) then
begin

...

También he ampliado los procedimientos ComprobarSeleccionComponentes, MoverOtrosSeleccionados, AmpliarComponenes, etc., es decir, en todo lo referente a la selección y movimiento de componentes (ya lo veréis en el proyecto).

CONFIGURANDO LA TABLA Y EL CAMPO

Una vez insertados los campos en el informe debemos dar la posibilidad al usuario de especificar el nombre del campo y de la tabla al que pertenece. Para ello voy a crear un nuevo formulario llamado FCampo con lo siguiente:


Para poder traernos los campos y tablas de la base de datos le he creado estas tres variables públicas:

public
{ Public declarations }
Campo: TQRDBText;
Tabla: TIBTable;
BaseDatos: TIBDatabase;

Estas variables nos las va a pasar el formulario FInforme cuando el usuario haga clic sobre un campo con la tecla SHIFT pulsada. He intentado asignarle un menú contextual a los objeto TQRDBText pero como no tienen la propiedad Popup no hay manera.

Así que en el procedimiento SeleccionarComponente compruebo si el usuario mantienen el botón SHIFT pulsado para abrir el formulario FCampo:

if (Seleccionado is TQRDBText) and
(HiWord(GetAsyncKeyState(VK_LSHIFT)) <> 0) then
ConfigurarCampo(Seleccionado as TQRDBText);

El procedimiento ConfigurarCampo le envía al formulario FCampo lo que necesita para trabajar:

procedure TFInforme.ConfigurarCampo(Campo: TQRDBText);
begin
// si no está conectado con la base de datos no hacemos nada
if not BaseDatos.Connected then
begin
Application.MessageBox('Conecte primero con la base de datos.',
'Acceso denegado', MB_ICONSTOP);
Exit;
end;

Application.CreateForm(TFCampo, FCampo);
FCampo.BaseDatos := BaseDatos;
FCampo.Campo := Campo;
FCampo.Tabla := Tabla;
FCampo.ShowModal;
end;

También comprueba si previamente hemos conectado con la base de datos. Dentro del formulario FCampo utilizo el evento OnShow para pedirle a la base de datos el nombre de las tablas:

procedure TFCampo.FormShow(Sender: TObject);
begin
// Nos traemos el nombre de todas las tablas
BaseDatos.GetTableNames(SelecTabla.Items, False);
end;

Cuando el usuario seleccione una tabla activando con el ComboBox SelecTabla el evento OnChange entonces vuelo a pedirle a la base de datos el nombre de los campos de la tabla seleccionada:

procedure TFCampo.SelecTablaChange(Sender: TObject);
begin
// Si no ha seleccionado ninguna tabla no hacemos nada
if SelecTabla.ItemIndex = -1 then
Exit;

// Le pedimos a la base de datos que nos de los campos de la tabla
BaseDatos.GetFieldNames(SelecTabla.Text, SelecCampo.Items);
end;

Una vez pulsamos el botón Aceptar le envío al objeto TQRDBText el campo y la tabla a la que pertenece:

procedure TFCampo.BAceptarClick(Sender: TObject);
begin
if SelecTabla.ItemIndex = -1 then
begin
Application.MessageBox('Debe seleccionar una tabla.',
'Atención', MB_ICONSTOP);
Exit;
end;

if SelecCampo.ItemIndex = -1 then
begin
Application.MessageBox('Debe seleccionar un campo.',
'Atención', MB_ICONSTOP);
Exit;
end;

Campo.DataField := SelecCampo.Text;
Tabla.TableName := SelecTabla.Text;
Campo.DataSet := Tabla;
Close;
end;

MODIFICANDO LA VISTA PREVIA

Cuando hagamos una vista previa del documento entonces debemos abrir la tabla de la base de datos antes de imprimir:

procedure TFInforme.VistaPreviaClick(Sender: TObject);
begin
// ¿Ha elegido el usuario una tabla?
if Tabla.TableName <> '' then
begin
// Entonces se la asignamos al informe
Informe.DataSet := Tabla;
Tabla.Close;
Tabla.Open;
end;

Informe.Preview;
end;

CAMBIAR EL NOMBRE DE LAS ETIQUETAS

Vamos a hacer una pequeña modificación más para poder cambiar el nombre de las etiquetas. Para ello volvemos a modificar el procedimiento SeleccionarComponente para que nos pida el nombre de la etiqueta al pincharla con el botón SHIFT pulsado:

if (Seleccionado is TQRLabel) and (HiWord(GetAsyncKeyState(VK_LSHIFT)) <> 0) then
begin
EtiSel := Seleccionado as TQRLabel;
sNombre := InputBox('Cambiar nombre etiqueta', 'Nombre:', '');
if sNombre <> '' then
EtiSel.Caption := sNombre;
end;

Con todo esto que he montado se puede hacer un pequeño informe a una banda con la ficha de un cliente:


Esta sería su vista previa:



EL PROYECTO

Aquí va el proyecto comprimido en RapidShare y Megaupload:

http://rapidshare.com/files/216858597/EditorInformes4_DelphiAlLimite.rar.html

http://www.megaupload.com/?d=AKDT45NN

También he incluido una base de datos creada con Firebird 2.0 con la tabla de CLIENTES. En el próximo artículo voy a finalizar esta serie dedicada a nuestro propio editor de informes añadiendo la posibilidad de grabar y cargar plantillas de informes.

Pruebas realizadas en RAD Studio 2007.

Publicidad