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.

6 comentarios:

Anónimo dijo...

oye amigo te keria preguntar, sabes komo utilizar un archivo 3DS en delphi y poderlo mover y ponerle texturas???? pro ejemplo un personaje hecho en 3D studio o Blender o similares, y ke lo guarde y luego desde la aplicacion pueda moverlo (komo un juego) y poderle poner texturas komo ropa y karas y demas........me podrias ayudar???

Administrador dijo...

Lo que estas pidiendo no es nada sencillo. Hay que cargar los objetos que están compuestos de triángulos con tres vértices cada uno (x,y,z) y con cada coordenada de la textura (u,v).

Yo ya he hecho esto en OpenGL (crear triángulos con texturas) pero desconozco el formato 3DS.

En la página:

http://nehe.gamedev.net/

hay información bastante interesante sobre OpenGL y 3D, que aunque está orientado al lenguaje C/C++ es fácil de entender.

De ahí aprendí todo lo que hace falta para OpenGL en Delphi.

Saludos.

Anónimo dijo...

molto gracie......digo muchas gracias karnal, a ver ke dia sigues tus cursos de programacion de juegos, estan bien interesantes......

Administrador dijo...

A ver si me toca la loteria y tengo más tiempo para escribir artículos (jeje).

Cada persona me pide una cosa distinta y no se puede satisfacer a todo el mundo.

Poco a poco.

Abismo Neo dijo...

pues no te preokupes, es ke me gustaria hacer un tipo de juego 3D de lucha libre, parecido al WRESTLING ENCORE, ya estoy leyendo y buscando info, y no konsidero ke sea facil, pero pues seria un buen proyecto ke tendria para desarrollar.

Si tuviera ayuda komo tus tutoriales ke konsidero muy bien explikados debido a ke son hechos por alguien ke sabe y no solo un tutorial TECNICO muy kuadrado; seria muy genial kontar kon esa ayuda pero tampoco te preokupes, me gusta programar, pero sin embargo me gusta mas orientarme a kosas de diseño y de juegos.

El problema es ke en el trabajo me piden kosas de WEB komo prototype, ruby , jquery y kosas asi, asi ke se me hace bolas todo el asunto....

pero si pudieras orientarme en algunas kosas no me molestaria.....

saludos amigo y no kumplas tantos kaprichos, ve a tu propio paso.

Administrador dijo...

Te recomiendo que empieces por proyectos pequeños y abarcables ya que si coges algo grande nunca lo vas a terminar.

Yo cometí el fallo de tirarme directamente a las 3D y hacer un motor tipo Doom y de hecho lo hice, pero es tanto el trabajo que hay que hacer y los fallos que hay que corregir que al final te desanimas y abandonas.

Lo mejor es coger proyectos pequeños 2D e ir avanzando a juegos cada vez más sofisticados antes de llegar a los 3D.

Saludos y mucha suerte.

Publicidad