28 noviembre 2008

Leyendo datos de hojas de cálculo de Microsoft Excel

Si hay algo que nos piden frecuentemente a los programadores de gestión es poder recoger o enviar datos a los programas ofimáticos más populares: Microsoft Word, Microsoft Excel y Microsoft Access.

Lo más común suele ser leer datos de una hoja de cálculo y guardarlos en nuestra base de datos, aunque también tenemos la posibilidad de enviarle la información para que Excel nos haga una gráfica espectacular.

Una hoja de cálculo es realmente un libro que puede contener una o más hojas de cálculo:


A su vez, Microsoft Excel puede abrir varios libros a la vez.

EL COMPONENTE TEXCELAPPLICATION

En la paleta de componentes tenemos el componente de la clase TExcelApplication que se encuentra en la sección Servers:


Lo insertamos en el formulario donde vamos a hacer la importación y lo llamamos Excel para simplificar:


Supongamos que queremos leer esta hoja de cálculo:


Primero abrimos la hora de cálculo:

Excel.Workbooks.Open( ExtractFilePath( Application.ExeName ) + 'Hoja.xls',
EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam, 0 );

Hay que reconocer que la cantidad de parámetros que tiene el método Open es impresionante:


Aunque no hay que asustarse porque lo que necesitamos realmente es el primer parámetro (el nombre del archivo excel a abrir). Los demás son para elegir si queremos abrirlo en modo sólo lectura, introducir una contraseña, etc.

Una vez que hemos abierto la hora de cálculo tenemos que situarnos en la Hoja1. Para ello creamos las siguientes variables:

var
i: Integer;
si: String;
Hoja: _WorkSheet;

Las variables i y si son para recorrer las celdas de la hoja de cálculo y la variable Hoja va a apuntar a una hoja en concreto. En nuestro caso la primera:

Hoja := Excel.Worksheets.Item[1] as _WorkSheet;

Para leer información de las celdas de la hoja de cálculo tenemos que conocer las coordenadas horizontales (A,B,C,…) y las verticales (1,2,3,…). Cuando lea la información la voy a volcar a un componente ListView configurado con estas columnas:


Ahora sólo queda ir recorriendo cada fila hasta que encontremos una fila vacía:

i := 2;
si := IntToStr( i );
repeat
with ListView.Items.Add do
begin
SubItems.Add( Hoja.Range['A'+si,'A'+si].Value2 ); // Código
SubItems.Add( Hoja.Range['B'+si,'B'+si].Value2 ); // Nombre
SubItems.Add( Hoja.Range['C'+si,'C'+si].Value2 ); // CIF
SubItems.Add( Hoja.Range['D'+si,'D'+si].Value2 ); // Saldo
end;

Inc( i );
si := IntToStr( i );
until ( VarType( Excel.Range['A'+si,'A'+si].Value2 ) = VarEmpty );

La propiedad Value2 de cada celda devuelve un tipo Variant, por ello utilizo la función VarType para comprobar si lo que hay en la celda esta vacío (VarEmpty). De ese modo sabemos cuando hemos terminado de leer datos.

Por último cerramos la hoja de cálculo con:

Excel.Workbooks.Close( 0 );

Con esto ya hemos conseguido traernos la información de la hoja de cálculo:


Igualmente podemos escribir datos en cualquier celda de la hoja de cálculo con total naturalidad:

Hoja.Range['B2','B2'].Value2 := ‘TRANSPORTES GARCIA, S.L.’;

De esta manera podemos crear nuestras plantillas de hojas de cálculo con gráficas incluidas y desde Delphi le enviamos la información.

Pruebas realizadas en RAD Studio 2007.

23 comentarios:

goooooood girl dijo...

your blog is feel good......

Anónimo dijo...

impresionante blog sobre delphi, felizidades

Alejandro dijo...

muy interesante el post, si quiero hacer lo mismo pero con delphi.net, sabes como hacerlo?
gracias
saludos

Administrador dijo...

Que yo sepa, la versión para .NET no tiene la pestaña de componentes Servers donde se encuentra el que necesitamos: TExcelApplication.

Con el tiempo que lleva Delphi para .NET supongo que habrá algún componente de terceros (libre o de pago) que cumpla el mismo cometido.

Saludos.

Armormi dijo...

hola he estado leyendo el post. y como no pude encontrar el codigo para delphi.net decidi pasarme a delphi 6.
pero me dio error.

podrias colocar el codigo para ver como es que va colocado.. soy nueva en delphi
gracias

Armormi dijo...

hola he estado leyendo el post. y como no pude encontrar el codigo para delphi.net decidi pasarme a delphi 6.
pero me dio error.

podrias colocar el codigo para ver como es que va colocado.. soy nueva en delphi
gracias

Administrador dijo...

El código es precisamente el que aparece en este post. Lo que podría ocurrirte es que no tienes la versión de Office compatible con los componentes de Delphi 6.

Por ello recomiendo de Delphi 7 en adelante. Lo que hacen estos componentes es llamar a Excel directamente. Y si puedes, utiliza Office XP.

Saludos.

Antonio Espinosa dijo...

tengo delphi 7 y pongo tu codigo y me da este error [Error] main.pas(152): Undeclared identifier: 'VarType'

que hago?? gracias

Antonio Espinosa dijo...

[Error] main.pas(152): Undeclared identifier: 'VarType' me da este error que hago???

Administrador dijo...

Incluye en el apartado "uses" la unidad Variant.

Saludos.

Alex dijo...

Ha oido un programa interesante - reparar archivos xlsx en el Internet. La utiliza me ha gustado y yo he cargado de el Internet. El instrumento ha determinado mis problemas con xls files. Luego el programa tengo muchos posibilidades y gratis como recordo.

Ariel Macias dijo...

necesito modificar un archivo excel ya creado, pero que no fue guardado en disco... osea esta temporalmente en la memoria... hay alguna forma de hacer esto.

Javier dijo...

Hola:
he seguido las instrucciones al pie de la letra pero no se me muestra nada en el listview, pero ejecuto el programa paso a paso y va realizando todas las instrucciones, pero no muestra nada.¿Hay que modificar algo en el listview apartde de añadirle las columnas?
Un saludo y enhorabuena por el blog

Javier dijo...

Hola:
he seguido los pasos del post y no me muestra nada en el listview. Ejecuto el programa paso a paso y la verdad es que realiza todas las instrucciones pero no me muestra nada en el listview. ¿Hay algo mas que configurar en el listview a parte de crearle las columnas?
Utilizo delphi 7.
Un saludo y enhorabuena por el blog

Administrador dijo...

Comprueba si en el ListView tienes la propiedad ViewStyle con el valor vsReport.

Saludos.

The Ingenier dijo...

Como puedo saber la edición del office?
ya que esos parametros solo se pueden utilizar para office anteriores al 2007, en el office 2007 en adelante no funciona así.

Administrador dijo...

Ese es uno de los problemas que no se como resolver, porque ya de manera predeterminada tienes que utilizar unos componentes para Office según su versión (2000, XP, etc.).

Es algo que en Delphi siempre he visto como algo chapucero.

Saludos.

Unknown dijo...

Muchas gracias, la verdad que me ha sido de gran ayuda. Muy buen trabajo.

Tlamatini dijo...

En mi codigo cuando lo compilo tengo el error 5: Argumento o llamada a procedimiento no válido. Aunque tambien en mi codigo en la linea Excel.Workbooks.Open( ExtractFilePath( Application.ExeName ) + '\77.xls', me marca el error Undeclared identifier 'Value' at linea 57. Te muestro mi codigo, por cierto estoy usando delphi 2010, ojala y si me puedas ayudar ya que lo unico que quiero es leer un archivo xls para que despues lo guarde en un archivo txt. Y en este ejemp´lo tu lees un archivo xls. De antemano gracias
Los elementos que use son:
-TButon
-TExcelApplication
-ListView

unit U_Principal;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtDlgs, StdCtrls, OleServer, Excel2000, ComCtrls, ShellApi,ComObj;



type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
OpenTextFileDialog1: TOpenTextFileDialog;
Button2: TButton;
ListView1: TListView;
Excel: TExcelApplication;
Button3: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;
path: String;
implementation

{$R *.dfm}
procedure TForm1.Button3Click(Sender: TObject);
var
i: Integer;
si: String;
Hoja: _WorkSheet;
begin
Excel.Workbooks.Open( ExtractFilePath( Application.ExeName ) + '\77.xls',
EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, 0 ); //EmptyParam, EmptyParam,
Hoja := Excel.Worksheets.Item[1] as _WorkSheet;

i := 2;
si := IntToStr( i );
repeat
with ListView1.Items.Add do
begin
SubItems.Add( Hoja.Range['A'+si,'A'+si].Value2 ); // Código
SubItems.Add( Hoja.Range['B'+si,'B'+si].Value2 ); // Nombre
SubItems.Add( Hoja.Range['C'+si,'C'+si].Value2 ); // CIF
SubItems.Add( Hoja.Range['D'+si,'D'+si].Value2 ); // Saldo
end;

Inc( i );
si := IntToStr( i );
until ( VarType( Excel.Range['A'+si,'A'+si].Value2 ) = VarEmpty );
end;

end.

Martín Lillo dijo...

Espectacular!!! Ahora, lo único que me sucedió, es que en el ListView, los datos me los muestra a partir de la segunda columna, y estoy perdiendo el último valor, y por supuesto, los datos están desfazados un lugar respecto a las columnas.
Qué me falta tocar?
Mil gracias!!!

Unknown dijo...

Hoja := Excel.Worksheets.Item[1] as _WorkSheet; amigo en esta linea me da un error que dice interface not supported :/

Unknown dijo...

buenas tardes, he aplicado el código, y funciona; sin embargo me obliga a colocar el archivo de excel en el directorio projects sin embargo quiero colocar el archivo donde tengo mi proyecto, ya probé con chdir y con setcurrentdir pero nada, agradecería una orientación al respecto

Unknown dijo...

Excelente tutorial.. Lo hice sin problemas

Publicidad