把資料從表中導入到EXCEL中

来源:互联网 发布:自媒体 知乎 编辑:程序博客网 时间:2024/04/30 11:25
法一:

unit main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ZAbstractRODataset, ZAbstractDataset, ZDataset, DB, DBClient,
Provider, GridsEh, DBGridEh, RzPanel, RzStatus, ExtCtrls, ZConnection,
BusinessSkinForm, StdCtrls, RzLabel, RzEdit, RzButton, DBCtrls, RzDBNav,
ImgList, Grids, DBGrids,ShellAPI, Mask, RzTray;

type
Tmainfrm = class(TForm)
BSFrmExcel: TbsBusinessSkinForm;
Connect: TZConnection;
pnlExcel: TRzPanel;
RzStatusBar1: TRzStatusBar;
RzToolbar1: TRzToolbar;
RzStatusPane1: TRzStatusPane;
RzClockStatus1: TRzClockStatus;
grbxShow: TRzGroupBox;
dbgExcel: TDBGridEh;
dscExcel: TDataSource;
DtStExcel: TDataSetProvider;
cdsExcel: TClientDataSet;
qryExcel: TZQuery;
mmSQL: TRzMemo;
lblSQL: TRzLabel;
RzSpacer1: TRzSpacer;
btnContron: TRzToolButton;
RzSpacer2: TRzSpacer;
btnExcelInt: TRzToolButton;
RzSpacer3: TRzSpacer;
btnExcelOut: TRzToolButton;
btnExit: TRzToolButton;
RzSpacer4: TRzSpacer;
NvgtrExcel: TRzDBNavigator;
ImgLstExcel: TImageList;
btnRfresh: TRzToolButton;
RzTrayIcon1: TRzTrayIcon;
procedure btnExitClick(Sender: TObject);
procedure btnExcelOutClick(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure mmSQLKeyPress(Sender: TObject; var Key: Char);
procedure btnRfreshClick(Sender: TObject);
procedure btnContronClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
mainfrm: Tmainfrm;

implementation

{$R *.dfm}

procedure Tmainfrm.btnExitClick(Sender: TObject);
begin
close;
end;

procedure Tmainfrm.btnExcelOutClick(Sender: TObject);
var
strTemp:string;
strSQL:string;
f:TextFile;
i,j:integer;
begin
strSQL:=mmSQL.Text;

with qryExcel do
begin
//======
Close;
SQL.Clear;
SQL.Add(strSQL);
Open;
cdsExcel.Active := false;
cdsExcel.Active := true;
//===
try
AssignFile(f,'ExcelTable/Excel.xls');
Rewrite(f);
//====
First;
strTemp := '';
//====
for i := 0 to Fields.Count - 1 do
begin
//====
if Fields[i].FieldName <> '' then
//====
if Fields[i].FieldName = 'ID' then
strTemp := strTemp + ''+#9 //====
else
strTemp := strTemp + Fields[i].FieldName + #9;
end;
Writeln(f,strTemp);
//====
for i := 0 to RecordCount - 1 do
begin
//====
strTemp := '';
for j := 0 to Fields.Count - 1 do
begin
//====
if Fields[j].FieldName <> '' then
strTemp := strTemp + fields[j].AsString + #9;
end;
//====
Writeln(f,strTemp);
//====
Next;
end;
finally
CloseFile(f);
end; //====End File Try
end;
//====
ShellExecute(0,nil,'ExcelTable/Excel.xls',nil,nil,0);
//====
//Application.Terminate;
end;

procedure Tmainfrm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Connect.Connected := false;
end;

procedure Tmainfrm.mmSQLKeyPress(Sender: TObject; var Key: Char);
begin
if key = #13 then
btnExcelOutClick(Sender);
end;

procedure Tmainfrm.btnRfreshClick(Sender: TObject);
begin
mmSQL.Text := '';
mmSQL.Text := 'select * from ';

end;

procedure Tmainfrm.btnContronClick(Sender: TObject);
begin
if cdsExcel.Active then
cdsExcel.Close
else
cdsExcel.Open;

end;

end.


**************************************************************************************************************************************************************************

方法二:

如何把数据输入到excel特定的表格中
Delphi作为一个出色的RAD,强大的数据库功能是其最重要的特

色之一,但是操纵困难的QuickReport控件常常不能满足数据库

报表的需要。如果你的报表非常复杂,或者要求灵活地改变格式

,那么使用Excel作为报表服务器是一个不错的选择。Delphi从

版本5开始提供的Excel组件极大地简化了OLE自动化技术的应用

。不过缺漏多多的帮助文件一直是Delphi最令人诟病的地方,这

些新组件也不例外,本文试图对此作一较详细地介绍。
Excel的对象模型是一个树状的层次结构,根是应用程序本身,

工作簿WorkBook是根对象的属性对象,本文主要讨论的用于数据

交换的WorkSheet则是工作簿的属性对象,详情参阅MSOffice提

供的Excel VBA帮助文件。在Delphi中控制Excel首先要与服务器

程序建立连接,打开工作簿,然后与目标工作表交换数据,最后

断开连接。

打开Excel工作簿
  我们的例子从一个带有TStringGrid(当然要填上一些数据

)和两个按钮的主窗体开始,从控制面板的Servers页签中拖一

个TExcelApplication控件放到窗体上。首先把ConnectKind设为

ckRunningOrNew,表示如果能够检测到运行的Excel实例则与其

建立联系,否则启动Excel。另外,如果希望程序一运行即与服

务器程序建立联系,可以把AutoConnect属性设为True。
与Excel建立联系只要一条语句就可以了:
Excel . Connect;
也许你已经注意到Servers页签上还有其他几个Excel控件,这些

控件通过ConnectTo方法可以与前面的Excel联系在一起:
ExcelWorkbook1.ConnectTo(Excel . ActiveWorkbook);
ExcelWorksheet1.ConnectTo(Excel . ActiveSheet as

_Worksheet);
ExcelWorksheet2.ConnectTo(Excel . Worksheets.Item

['Sheet2'] as _Worksheet);
要注意,使用ConnectTo方法前必须先打开相应的工作簿或工作

表,另外这些控件在多数情况下并不会带来额外的便利,因此最

好只使用一个TExcelApplication。
一旦与Excel服务器建立联系,就可以创建新的工作簿:
var
wkBook : _WorkBook;
LCID : Integer;
...
LCID := GetUserDefaultLCID();
wkBook := Excel.Workbooks.Add(EmptyParam, LCID);
Add函数的第一个参数用于定义新建工作簿所使用的模板,可以

使用xlWBATChart、xlWBATExcel4IntlMacroSheet、

xlWBATExcel4MacroSheet或者xlWBATWorksheet常量,也可以是

已有的xls文件名。这里的EmptyParam是Variants单元与定义的

变量,表示使用默认的通用模板创建新工作簿。
如果打开已有的xls文档,则应把要打开的文件名作为第一个参

数传递给Open函数:
wkBook:=Excel.WorkBooks.Open

(edtDesFile.text,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,LCID);
要知道,所有的数据操作主要是针对活动工作表而言的,下面的

语句使用一个_WorkSheet变量代表当前的活动单元格。如果知道

工作表的名称,其中的索引号可以用工作表名代替:
wkSheet:=wkBook.Sheets[1] as _WorkSheet;
完成数据交换后需要保存工作簿:
Excel.ActiveWorkBook.SaveAs ('MyOutput',

EmptyParam,EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, LCID);
或者:
Excel.ActiveWorkBook.Save(LCID);
最后要关闭工作簿并断开与Excel的连接:
wkBook.Close(True, SaveAsName, EmptyParam, LCID);
//Excel.Quit;
Excel.Disconnect;
这里的Close方法包含有保存的功能,第一个参数说明在关闭工

作簿之前是否保存所做的修改,第二个参数给出要保存的文件名

,第三个参数用于多位作者处理文档的情况。第二行要求终止

Excel的运行。

与工作表交换数据
  输入数据是对活动工作表的某个单元格或区域进行的,

Range与cells都是工作表的对象属性。Cells是单元格的集合,

如果没有指定具体位置可以代表整个工作表的所有单元格,但一

般使用它是为了引用某个具体的单元格,比如WS.Cells.Item

[1,1]就表示最左上角的单元格A1,注意在VBA中Item是Cells的

默认属性可以省略,但在Delphi中就没有这种便利了。为单元格

赋值要引用其Value属性,不言而喻,该属性是一个Variant变量

,例如:
wkSheet.Cells.Item[1, 1].Value := '通讯录';
当然你也可以为单元格指定公式:
var
AFormula:String;
……
AFormula:='=Rand()';
wkSheet.Range['F3','G6'].Value:=AFormula;
上面的方法非常直接简单,但是速度非常慢,不适合作大型报表

。那么能不能把所有的数据依次传递给Excel呢?我们可以使用

Range,这个对象代表工作表中的一个区域,象我们用鼠标拖出

的那样,一般是一个矩形区域,只要给定其左上角和右下角单元

格的位置就可以了,如Range['C3','J42']。
这里还有一个小问题,因为如果数据超出26列(比如有100列)

或者需要在运行中确定目标区域范围的话,使用字符名称标记单

元格就比较麻烦。回想一下,既然"C3"是单元格的标记,那么我

们当然也可以使用Cells,比如Range[Cells.Item[1,1],

Cells.Item[100,100]]。
可以想象,Range的值应该是数组,但是绝对不能用Delphi中的

Array给它赋值!要记住,在Delphi中,Excel对象的值总是

Variant类型的。
var
Datas : Variant;
Ir, ic: Integer;
……
Datas:= varArrayCreate([1,ir,1,ic],varVariant); //这里创

建100*100的动态数组
…… //这里为数组元素赋值
with wkSheet do
Range[cells.Item[3,1],cells.Item[ir+2,ic]].Value:=Datas;
要注意,工作表与Range都有Cells属性,为了明确起见,这里使

用了with语句。此外,Range是有方向性的,用VarArrayCreate

建立的一维数组只能赋给单行的Range,如果要为单列的Range定

义值,必须使用二维数组,比如:
Datas:=VarArrayCreate([1,100,1,1], varVariant);//创建

100*1的动态数组。
顺便提一下,Cells.Item[]实际上返回的也是Range对象。
从工作表中取回数据基本上是写数据的逆过程,稍微需要注意的

是如何确定工作表的数据范围:
var
ir, ic : Integer;
……
wkSheet.Cells.SpecialCells

(xlCellTypeLastCell,EmptyParam).Activate;
ir := Excel.ActiveCell.Row;
ic := Excel.ActiveCell.Column;
这里巧妙地利用特殊单元格函数SpecialCells取得包含数据的最

后一个单元格。

数据编辑
下面是数据编辑的两个例子。
var
DestRange: OleVariant;
begin
DestRange := Excel.Range['C1', 'D4'];
Excel.Range['A1', 'B4'].Copy(DestRange);
上面的例子复制了8个单元格的内容。如果给Copy函数传递一个

空参数,则该区域的数据被复制到剪贴板,以后可以用Paste方

法粘贴到别的位置。
var
WS: _Worksheet;
……
Excel.Range['A1', 'B4'].Copy(EmptyParam); //在一个工作表

中复制数据到剪贴板
WS := Excel.Activesheet as _Worksheet; //改变活动工作表
WS.Range['C1', 'D4'].Select;
WS.Paste(EmptyParam, EmptyParam, lcid); //把剪贴板中的内

容粘贴到新的工作表中

格式设置
选择Excel作为报表服务器主要是因为它强大的格式化能力。我

们首先把标题"通讯录"进行单元格合并,居中显示,然后修改字

体为18磅的"隶书",粗体:
with wkSheet.Range['A1','D1'],Font do
begin
Merge(True); //合并单元格
HorizontalAlignment:= xlCenter;
Size:=18;
Name:='隶书';
FontStyle:=Bold;
end;


如果单元格内容较长,将有部分内容无法显示,通常的做法是双

击选定区域右侧的边线是各列的宽度自动适应内容的长度。在

Delphi中通过AutoFit方法也可实现自适应的列宽行高,需要注

意的是该方法仅能用于整行整列,否则会提示OLE方法拒绝执行

的错误:
wkSheet.Columns.EntireColumn.AutoFit;
中式报表通常需要上下封顶的表格线,可以使用Borders集合属

性。要注意,VBA中的集合对象通常都有一个缺省的Item属性,

Delphi中是不能省略的。Weight属性用于定义表格线的粗细:
with Aname.RefersToRange,Borders do
begin
HorizontalAlignment:= xlRight;
Item[xlEdgeBottom].Weight:=xlMedium;
Item[xlEdgeTop].Weight:=xlMedium;
Item[xlInsideHorizontal].Weight:=xlThin;
item[xlInsideVertical].Weight:=xlThin;
end;

页面设置与打印
  页面设置是通过工作表的PageSetUp对象属性设置的。Excel

VBA中预设了40余种纸张常量,需要注意的是某些打印机只支持

其中的一部分纸张类型。属性Orientation用于控制打印的方向

,常量landscape = 2表示横向打印。布尔属性

CenterHorizontally和CenterVertically用于确定打印的内容是

否在水平和垂直方向上居中。
with wkSheet.PageSetUp do
begin
PaperSize:=xlPaperA4; //Paper type A4
PrintTitleRows := 'A1:D1'; //Repeat this row/page
LeftMargin:=18; //0.25" Left Margin
RightMargin:=18; //0.25" will vary between printers
TopMargin:=36; //0.5"
BottomMargin:=36; //0.5"
CenterHorizontally:=True;
Orientation:=1; //横向打印(landscape)=2, portrait=1
end;
打印报表可以调用工作表的PrintOut方法,VBA定义的该方法共

有8个可选参数,前两个用于规定起止页,第三格式打印的份数

,不过在Delphi中为其在最后增加了一个LCID参数,而且该参数

不能使用EmptyParam。类似地,打印预览方法PrintPreview在

VBA中没有参数,而在Delphi中调用需要两个参数。
// wkBook.PrintPreview(True,LCID); //for previewing
wkSheet.PrintOut(EmptyParam,EmptyParam,1,
EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,LCID);

命名区域与宏
如果报表的格式比较复杂,为特定的表格区域命名然后按名引用

是一种比较好的方法。Names是WorkBook的一个集合对象属性,

它有一个的Add方法可以完成这项工作。
Var
Aname : Excel2000.Name;
……
Aname := wkBook.Names.Add('通讯录','=Sheet1!$A$3:$D$7',

EmptyParam, EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam);
其中Add函数的第一个参数是定义的名称,第二个参数是名称所

表示的单元格区域。要注意区域名称的类型必须使用限定符,如

果使用类型库(D4),则限定符为Excel_TLB。此外,命名的区

域应使用绝对引用方式,即加上"___FCKpd___0quot;符号。
一旦命名了一个区域,就可以使用这个名称来引用它,下面的一

行代码使通讯录内容以粗体显示:
AName.RefersToRange.Font.Bold:=True;
不过最令人惊喜的也许是你能够在Delphi中动态地修改Excel宏

程序!下面的代码为我们的工作簿创建了一个宏,在关闭工作簿

时记录上一次访问的时间:
var
LineNo: integer;
CM: CodeModule;
sDate:String;
begin
CM := WkBook.VBProject.VBComponents.Item

('ThisWorkbook').Codemodule;
LineNo := CM.CreateEventProc('BeforeClose', 'Workbook');
SDate:='上次访问日期:'+DateToStr(Date());
CM.InsertLines(LineNo + 1, ' Range("B2").Value =

"'+sDate+'"');
End;
修改宏需要在前面的uses一节加上一个单元:VBIDE2000,如果

使用类型库则相应的单元为VBIDE_TLB。这段代码的关键是

CodeModule对象,遗憾的是在Excel VBA help文中找不到该对象

的踪迹,只能去检索MSDN了。

Delphi4及以前的版本
Delphi4没有提供TExcelApplication对象,需要引入类型库使用

OLE自动化技术,Excel97的类型库是Excel8.olb。这两种方法的

主要区别在于与服务器程序建立连接的方法,下面是通过类型库

控制Excel的程序框架:
uses Windows, ComObj, ActiveX, Excel_TLB;
var
Excel: _Application;
LCID: integer;
Unknown:IUnknown;
Result: HResult;
begin
LCID := LOCALE_USER_DEFAULT;
Result := GetActiveObject(CLASS_Application, nil,

Unknown); //尝试捕获运行中的程序实例
if (Result = MK_E_UNAVAILABLE) then
Excel := CoApplication.Create //启动新的程序实例
else begin
{检查GetActiveObject方法调用过程中的错误}
OleCheck(Result);
OleCheck(Unknown.QueryInterface(_Application, Excel));
end;

…… //进行数据处理

Excel.Visible[LCID] := True;
// Excel.DisplayAlerts[LCID] := False; //显示提示对话框
Excel.Quit;
End;
这里没有采用通常的try…except结构,是因为例外处理机制要

进行复杂的OLE检查,降低了except部分的执行速度。要注意,

不同的Delphi版本生成的伴随函数CoApplication和一些常量名

可能不同,应查看相应的类型库。在调用Quit方法之前,一定要

释放程序中创建的所有工作簿和工作表变量,否则Excel可能驻

留在内存中运行(可以按下Ctrl+Alt+Del查看)。调用

GetActiveObject捕获程序实例还有一个小问题,如果Excel处于

最小化运行状态,可能出现只显示程序主框架而用户区不可见的

情况。
此外,如果不希望引入类型库,还可以采用滞后绑定的方法,不

过速度要慢许多。下面的例子声明了一个Variant变量来代表

Excel应用程序:
var
Excel: Variant;
……
try
Excel := GetActiveOleObject('Excel.Application');
except
Excel := CreateOleObject('Excel.Application');
end;
Excel.Visible := True;
采用滞后绑定时,编译器不对调用的Excel对象方法进行检查,

而把这些工作交给服务器程序在执行时完成,这样VBA所设置的

大量默认参数(经常有十几个)就发挥了应有的作用,因此这种

方法有一个意料不到的好处--代码简洁:
var
WBk, WS, SheetName: OleVariant;
.…..
WBk := Excel.WorkBooks.Open('C:/Test.xls');
WS := WBk.Worksheets.Item['SheetName'];
WS.Activate;
……
WBk.Close(SaveChanges := True);
Excel.Quit;
除了运行速度慢以外,如果要使用类型库中定义的常量,就只能

自己动手了:
const
xlWBATWorksheet = -4167;
……
XLApp.Workbooks.Add(xlWBatWorkSheet);
最后不要忘记关闭Excel之后释放变量:
Excel := Unassigned;


以下是本文例子中所用的源代码,在Delphi6+MSOffice2000下通

过。
unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes,

Graphics, Controls, Forms,
Dialogs, OleServer, Excel2000, Grids, StdCtrls;

type
TForm1 = class(TForm)
Button1: TButton;
StringGrid1: TStringGrid;
Excel: TExcelApplication;
procedure FormActivate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }

procedure Write2Xls;
procedure OpenExl;
procedure CloseExl;
procedure AddFormula;
procedure NameSheet;
procedure Formats;
procedure AddMacro;
procedure Retrieve;
procedure Printit;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}
uses
VBIDE2000;

var
ir,ic:Integer;
wkSheet:_WorkSheet;
LCID:Integer;
wkBook:_WorkBook;
AName:Excel2000.Name;

procedure TForm1.FormActivate(Sender: TObject);
begin
with StringGrid1 do
begin
Rows[0].CommaText:='姓名,性别,年龄,电话';
Rows[1].CommaText:='张三,男,25,010-33775566';
Rows[2].CommaText:='李四,男,47,012-6574906';
Rows[3].CommaText:='周五,女,18,061-7557381';
Rows[4].CommaText:='孙涛,女,31,3324559';
end;
end;

procedure TForm1.OpenExl;
begin
with Excel do
begin
Connect;
LCID:=GetUserDefaultLCID();
wkBook:=WorkBooks.Add(EmptyParam,LCID);
wkSheet:=wkBook.Sheets[1] as _WorkSheet;
end;
end;

procedure TForm1.Write2Xls;
var
Datas:Variant;
i,j:Integer;
begin
ir:=StringGrid1.RowCount;
ic:=StringGrid1.ColCount;
Datas:=varArrayCreate([1,ir,1,ic],varVariant);
for i:=1 to ir do
for j:=1 to ic do
Datas[i,j]:=StringGrid1.Cells[j-1,i-1];

with wkSheet do
begin
Activate(LCID);
Cells.Item[1,1].Value:='通讯录';
Range[cells.Item[3,1],cells.Item

[ir+2,ic]].Value:=Datas;
end;
// Excel.Visible[LCID]:=True;

Datas:=Unassigned;
end;

procedure TForm1.Retrieve;
var
Datas:Variant;
i,j:Integer;
begin
with wkSheet do
begin
Cells.SpecialCells

(xlCellTypeLastCell,EmptyParam).Activate;
ir:=Excel.ActiveCell.Row;
ic:=Excel.ActiveCell.Column;
Datas:=Range[Cells.Item[1,1],Cells.Item[ir,ic]].Value;
with StringGrid1 do
begin
ColCount:=ic;
RowCount:=ir;
ScrollBars:=ssBoth;
for i:=0 to ir-1 do
for j:=0 to ic-1 do
Cells[j,i]:=Datas[i+1,j+1];
end;
Datas:=UnAssigned;
end;
end;

procedure TForm1.CloseExl;
const
SaveAsName='test.xls';
begin
wkBook.Close(True,SaveAsName,EmptyParam,LCID);
Excel.Quit;
Excel.Disconnect;
end;

procedure TForm1.NameSheet;
begin
AName:=wkBook.Names.Add('通讯录','=Sheet1!

$A$3:$D$7',EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,EmptyParam);
end;

procedure TForm1.AddFormula;
var
AFormula:String;
begin
AFormula:='=Rand()';
wkSheet.Range['F3','G6'].Value:=AFormula;
end;

procedure TForm1.Formats;
begin
with wkSheet.Range['A1','D1'],Font do
begin
Merge(True); //合并单元格
HorizontalAlignment:= xlCenter;
Size:=18;
Name:='隶书';
FontStyle:=Bold;
end;
wkSheet.Columns.EntireColumn.AutoFit;
with Aname.RefersToRange,Borders do
begin
HorizontalAlignment:= xlRight;
Item[xlEdgeBottom].Weight:=xlMedium;
Item[xlEdgeTop].Weight:=xlMedium;
Item[xlInsideHorizontal].Weight:=xlThin;
item[xlInsideVertical].Weight:=xlThin;
end;
end;

procedure TFOrm1.AddMacro;
var
LineNo: integer;
CM: CodeModule;
sDate:String;
begin
CM := WkBook.VBProject.VBComponents.Item

('ThisWorkbook').Codemodule;
LineNo := CM.CreateEventProc('BeforeClose',

'Workbook');
SDate:='上次访问日期:'+DateToStr(Date());
CM.InsertLines(LineNo + 1, ' Range("B2").Value =

"'+sDate+'"');
end;

procedure TForm1.Printit;
begin
with wkSheet.PageSetUp do
begin
PaperSize:=xlPaperA4; //Paper type A4
PrintTitleRows := 'A1:D1'; //Repeat this row/page
LeftMargin:=18; //0.25" Left Margin
RightMargin:=18; //0.25" will vary between printers
TopMargin:=36; //0.5"
BottomMargin:=36; //0.5"
CenterHorizontally:=True;
Orientation:=1; //横向打印(landscape)=2, portrait=1
end;

wkSheet.PrintOut(EmptyParam,EmptyParam,1,
EmptyParam,EmptyParam,EmptyParam,
EmptyParam,EmptyParam,LCID);

end;

procedure TForm1.Button1Click(Sender: TObject);
begin
try
OpenExl;
Write2xls;
AddFormula;
NameSheet;
Formats;
PrintIt;
AddMacro;
ReTrieve;
finally
CloseExl;
end;
end;

end.

**************************************************************************************************************************************************************************

方法三:

在Delphi中创建的简单的Excel报表类
作为一个开发各种信息系统的程序员,写报表是家常便饭的事,

以至于曾经写个一个为报表而报表的项目^_^
我用过报表的控件不多,用过Quick Report,Rave Report还有

以前用VB时用过十分低版本的Crystal Report,当然还有这篇文

章的主角Excel。Excel做报表有什么好处与坏处。我就不说了,

大家都明白。(写了浪费大家时间)
在Delphi中有专门的控件去调用Word、Excel等的Office组件。

但这些控件的功能太多了,之间又有不少的联系,如果只是为调

用Excel生成报表的话,我觉得还不如我自己这个类方便。
我先来介绍一下我这个类的用法,各位看官,主看以下代码:

procedure TForm1.FormCreate(Sender: TObject);
begin
AFER := TFlexExcelReport.Create;
AFER.ModelFile := ExtractFilePath(Application.ExeName)

+ 'Book1.xls';
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
AFER.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
p1, p2 : TPoint;
begin
p1.X := 2;
p1.Y := 3;
p2.X := 10;
p2.Y := 20;
AFER.Connect;
AFER.Cells[1, 2] := 'FlexExcelReport Test';
AFER.SelectCell(1, 2);
AFER.Copy;
AFER.SelectRange(p1, p2);
AFER.Paste;
AFER.SelectCell(1, 2);
AFER.Clear;
AFER.SetPrintArea(p1, p2);
end;
程序运行后,点击Button2,就会马上创建一个Excel的实例,这

个实例是以Book1.xls为模板来打开的,打开后Excel会自动把这

个文档命名为Book11。然后在1,2这个格里面填入内容,选择这

个格子,复制,跟着选择2,3 -10,20这个区域,把刚才复制在

剪贴板的内容复制进去。接下来就清除掉1,2中的内容,最后设

置打印区域。
每次点击Button2都会重复上面的操作。反正用户点击多少次

Button2,就会生成多少个Excel的实例。你不必担心,当你退出

这个程序时,这些Excel都会随之关闭并释放对像。这里为什么

要以Book1.xls为模板呢?原因是我懒,我不想用Delphi操纵

VBscript,在空白的WorkSheet中画报表(这是一件会做死人的

事)。而是先把报表的式样画好在Book1.xls中,这样每次只要

用Delphi填内容就可以了。
是不是很简单呢?(我不是黄婆,不过还是要自夸一下!)

下面是整个FlexExcel Unit的内容:
unit FlexExcel;

interface
uses
SysUtils, Classes, Types, ComObj, Variants;
type
TFlexExcelReport = class(TObject)
private
FList: TList;
FModelFile: string;
function CoordsToXLS(ACol, ARow: integer): string;
procedure SetCells(ACol, ARow: Integer; const Value:

string);
public
constructor Create;
destructor Destroy; override;
procedure Clear;
function Connect: Boolean;
procedure Copy;
procedure Paste;
procedure SelectCell(ACol, ARow : integer);
procedure SelectRange(TopLeft, RightBottom :

TPoint);
procedure SetPrintArea(TopLeft, RightBottom :

TPoint);
property Cells[ACol, ARow: Integer]: string write

SetCells;
property ModelFile: string read FModelFile write

FModelFile;
end;

implementation

type
TFlexExcelHandle = class(TObject)
private
FConnected: Boolean;
FXlsHandle: Variant;
end;

{
******************************* TFlexExcelReport

*******************************
}
constructor TFlexExcelReport.Create;
begin
FList := TList.Create;
end;

destructor TFlexExcelReport.Destroy;
var
i: Integer;
hd: TFlexExcelHandle;
begin
for i := 0 to FList.Count - 1 do
begin
hd := FList[i];
if hd.FConnected then
begin
hd.FXlsHandle.DisplayAlerts := false;
hd.FXlsHandle.Quit;
hd.FXlsHandle := UnAssigned;
end;
hd.Free;
end;
FList.Free;
inherited;
end;

procedure TFlexExcelReport.Clear;
begin
TFlexExcelHandle(FList[FList.Count -

1]).FXlsHandle.Selection.Clear;
end;

function TFlexExcelReport.Connect: Boolean;
var
hd: TFlexExcelHandle;
begin
result := false;
hd := TFlexExcelHandle.Create;
try
hd.FXlsHandle := CreateOleObject

('Excel.Application');
hd.FConnected := true;
except
on E : Exception do
begin
hd.Free;
exit;
end;
end;
hd.FXlsHandle.Visible := true;
hd.FXlsHandle.Workbooks.Add [FModelFile];
FList.Add(hd);
result := true;
end;

function TFlexExcelReport.CoordsToXLS(ACol, ARow:

integer): string;
var
i: Integer;
begin
result := '';
i := (ACol - 1) div 26;
if i > 0 then result := Chr(64 + i);
i := (ACol - 1) mod 26;
result := result + Chr(64 + i + 1) + IntToStr(ARow);
end;

procedure TFlexExcelReport.Copy;
begin
TFlexExcelHandle(FList[FList.Count -

1]).FXlsHandle.Selection.Copy;
end;

procedure TFlexExcelReport.Paste;
begin
TFlexExcelHandle(FList[FList.Count -

1]).FXlsHandle.ActiveWorkBook.ActiveSheet.PasteSpecial;
end;

procedure TFlexExcelReport.SelectCell(ACol, ARow :

integer);
begin
TFlexExcelHandle(FList[FList.Count -

1]).FXlsHandle.ActiveWorkBook.ActiveSheet.Range

[CoordsToXLS(ACol, ARow)].Select;
end;

procedure TFlexExcelReport.SelectRange(TopLeft,

RightBottom : TPoint);
begin
if (TopLeft.X = RightBottom.X) and (TopLeft.Y =

RightBottom.Y) then
SelectCell(TopLeft.X, TopLeft.Y)
else
TFlexExcelHandle(FList[FList.Count -

1]).FXlsHandle.ActiveWorkBook.ActiveSheet.Range

[CoordsToXLS(TopLeft.X, TopLeft.Y) + ':' + CoordsToXLS

(RightBottom.X, RightBottom.Y)].Select;
end;

procedure TFlexExcelReport.SetCells(ACol, ARow: Integer;

const Value: string);
begin
TFlexExcelHandle(FList[FList.Count -

1]).FXlsHandle.ActiveWorkBook.ActiveSheet.Cells[ARow,

ACol] := Value;
end;

procedure TFlexExcelReport.SetPrintArea(TopLeft,

RightBottom : TPoint);
begin
TFlexExcelHandle(FList[FList.Count -

1]).FXlsHandle.ActiveWorkBook.ActiveSheet.PageSetup.Prin

tArea := CoordsToXLS(TopLeft.X, TopLeft.Y) + ':' +

CoordsToXLS(RightBottom.X, RightBottom.Y);
end;

end.

**************************************************************************************************************************************************************************

方法四 Delphi控制Excel自动生成报表

摘 要:Excel是当前最流行的数据报表制作工具。本文介绍如何使用Delphi来控制Excel完成数据库与报表之间的数据交换,讨论了报表制作工程中的一些细节性问题。
关键字:Delphi,Excel,报表
1 引言
数据报表作为企事业单位上报和下达的重要信息载体,随着信息化建设的不断推进,在实际的工作中得到了前所未有的应用。因此,数据报表已经成为管理信息系统中重要的一项功能,并且,由于数据的多样性和统计信息的增加,数据报表的系统实现变得越来越复杂。
Delphi是一个高效的可视化数据库管理信息系统开发工具,.但是Delphi开发环境中提供的报表控件在制作复杂报表时显得不够理想,不管是以前版本提供的Quick Report控件组,还是Delphi 7提供的Rave控件组,都不能让用户对生成的报表进行改动,且程序控制很难实现。Excel作为现代办公常用的电子表格制作工具,以它的易操作性和实用性,得到了各行业办公人员的青睐。本文根据实际应用实践,介绍利用Delphi编程控制Excel生成报表的各种方法。
2 Delphi控制Excel的方法
2.1 创建Excel文件
要在Delphi中控制Excel,就必须用到OLE自动化。现在一般采用OLE2来创建OLE对象,当激活一个OLE对象时,服务器程序仅在容器程序内部激活,这就是所谓的“就地激活”(in-place activation)。
创建Excel文件时,先创建一个OLE对象,然后在对象中建立工作表worksheet,如函数createExcel所示:
function createExcel:variant;
var
v:variant;
sheet:variant;
begin
v:=createoleobject('Excel.Application');//创建OLE对象
v.visible:=true;
v.workbooks.add(-4167);//添加工作表
v.workbooks[1].sheets[1].name:='test';
sheet:=v.workbooks[1].sheets['test'];
return v;
end;
2.2 数据表格控制
Excel表格的控制,主要包括数据的导入、修改;单元格的合并、边框的控制;表格的复制、粘贴等。当报表格式一定的情况下,表格的复制、粘贴显得尤为重要,这样,可以先制作一个文件模板,然后按照实际需要输出多页报表即可。
(1)数据的导入(importData)
procedure importData;
var
I,j:integer;
v:variant;
begin
v:=createExcel; //创建Excel文件test
for I:=0 to maxcolumn do
begin
for j:=0 to maxrow do
v.workbooks[1].sheets[1].cells[I,j]:=I*j; //导入数据
end;
end;
(2)单元格的合并、边框的控制(lineStylecontrol)
单元格的合并,是在选定合并范围的情况下进行的。边框控制可以操作边框线条的是否显示。其他方式的控制,可以仿照下面过程进行。
procedure lineStylecontrol;
var
v,sheet,range:variant;
begin
v:=createExecl;
sheet:= v.workbooks[1].sheets[1];
range:=sheet.range[sheet.cells[1,1],sheet.cells[39,30]];//选定表格
range.select;
range.merge; //合并单元格
range.borders.linestyle:=xlcontinuous; //置边框线可见
range.font.size:=9; //改变表格内文本字体大小
end;
(3)表格的复制与粘贴(copyandPaste)
procedure copyandPaste;
var
v,sheet,range:variant;
begin
v:=createExecl;
sheet:= v.workbooks[1].sheets[1];
range:=sheet.range[sheet.cells[1,1],sheet.cells[39,30]];
range.select; //选定要复制的表格
range.copy; //复制选定的表格
sheet.range[sheet.cells[40,1],sheet.cells[40,1]].select; //选择要粘贴的位置
sheet.paste; //粘贴表格
end;
2.3 文件的保存
文件保存是在创建文件的基础上进行的,过程saveFile说明了文件保存过程中应该注意的问题:
procedure saveFile;
var
sheet,v:variant;
begin
v:=createExcel;
if savedialog.execute then
begin
v.workbooks[1].saveas(savedialog.FileName);//保存文件
v.workbooks[1].close; //关闭工作表
v.quit; //关闭Excel
v := unassigned;
end;
end;
3 报表制作应注意的问题
(1)报表格式的选择
报表格式的选择对信息系统报表的实现方法起着决定性的影响。如果在报表的格式要求比较严格的情况下,应当采用模板的方式产生报表。由于模板在数据导入之前就已经按照标准制定好,所以只要在程序中控制模板的复制与粘贴,然后编程实现数据输入指定位置即可。而对于报表格式多变的情况,由于数据的不同,需要合并单元格或者控制边框,可以直接在程序中自动控制报表的生成。
(2)打印
对于Excel报表的打印,最好不要在程序中进行控制,因为报表往往需要签字或者进行审查,有许多报表都包含平面图或示意图,为了有效的控制打印质量,最好通过程序控制输出或显示Excel文件,以便修改;另一个重要的原因是Excel具有强大的排版功能,而这正是选择Excel导出报表的重要原因。
(3)报表时间和表头
报表时间要有用户可以控制的输出。表头的制作要在事先做好格式,控制输出时,只改动那些诸如上报单位、下达单位、负责人等数据,这样既保证了系统的效率,又不失其实用性。
4 结论
用Delphi控制Excel来完成数据库管理信息系统的数据报表功能,是Delphi制作复杂报表的最佳选择,因为Delphi不但能控制数据的导出与导入,而且可以完成当前Excel应用中的大部分功能。如果深入研究Visual Basic for Application(VBA)就可以制作出符合实际需要的各种Delphi控制Excel的控件。

参考文献:
[1] Steve Teixeira,Xavier Pacheco.Delphi 6开发人员指南. 北京:机械工业出版社,2003.
[2] 刘忠恺,刘春.Delphi 5.0数据库开发应用教程. 北京:航空工业出版社,2000.
[3] Steve Teixeira,Xavier Pacheco.Delphi5 Developers Guide.Sams publishing,2000.