现在的位置: 首页 > 综合 > 正文

将数据集转换为Excel格式的一个实现

2013年08月08日 ⁄ 综合 ⁄ 共 5826字 ⁄ 字号 评论关闭

{
将数据集转换为Excel格式的一个实现

在做项目时,很多情况下,客户需要对我们保存在数据库中的数据再加工再利用,
如财务需要一份今年财务情况的电子报表,总经理需要今年销售情况的一个电子报表。
我们的程序可以把这些数据用DBGrid显示出来,也可以用QuickReport打印出来,但是
这些数据都不能被客户自由的完整地拷贝,没有独立的电子化形式,因而不能被独立地使用。

要把数据库中的数据,在Delphi中也就是数据集,转换为独立的电子化形式,
我们可以有几个选择:利用CLientDataSet把数据集保存为CDS文件或XML文件;自己做转换。

前者的这两种文件格式都需要专门的程序才能查看,虽然XML是通用的数据交换格式,
但是对于需要直接使用数据的一般客户却未必适用。因此我们需要把数据集转换为客户可以可以
轻易使用的文件格式。而微软的Office办公套件中的Excel是许多客户都比较熟悉的,因此我们
选择把数据集转换为Excel格式,然后让客户利用Excel的强大功能对数据进行浏览,再处理。
例如,客户利用这些数据来完全定制自己的报表,如加入丰富的排版格式和定制的标题,
添加数据的柱状视图等等。同时客户还可以在自己的各种办公软件如Word中把这些数据拷来拷去。

好了,我们开始设计吧。 首先确定目标需求:

输入:TDataSet或其派生类 (TTable,TQuery,TClientDataSet,TADODataSet...)
输入:Excel格式的文件 (*.xls)
特性:可以控制Excel是否可见,以便让用户马上可以看到Excel中的数据
可以控制TDataSet中的哪些字段不输出到Excel中去
包含字段标题

其中的关键是:如何生成一个Excel格式的文件以及如何往其中写入数据 ?

Excel可以用作OLE服务器,向外部输出某些属性,方法和事件。
Delphi可以利用这些功能,实现与Excel的集成。

微软的Excel对象模型包括了128个不同的对象,从矩形,文本框等简单的对象到透视表,图表等复杂的对象.
下面我们简单介绍一下其中最重要,也是用得最多的四个对象.这些都可以在Excel的VBA中找到完整的文档

1. Application对象
Application对象处于Excel对象层次结构的顶层,表示Excel自身的运行环境.
2. Workbook对象
Workbook对象直接地处于Application对象的下层,表示一个Excel工作薄文件.
3. Worksheet对象
Worksheet对象包含于Workbook对象,表示一个Excel工作表.
4. Range对象
Range对象包含于Worksheet对象,表示Excel工作表中的一个或多个单元格.
某一个单元格内的数据还可以用Sheet.Cells(Row,Col)来引用

在Delphi中,可以用OleVariant变量来创建这些对象。

为了控制哪些字段才能输出到Excel中去,我们利用字段的一个属性Tag,如果它小于
等于我们指定的某个值,就输出到Excel中去,否则不输出。如果你的DataSet没有添
加永久字段对象,那么所有字段的Tag值都是0。如果你添加了永久字段对象,就可以
控制每个字段的Tag值和输出标题的DisplayLabel属性。

具体的函数设计:
1、DataSetToExcelSheet : 把数据集转换到Sheet对象中,没有用户界面。
2、DataSetToExcel :调用DataSetToExcelSheet,把数据集转换到Excel文件中,
具有用户界面,如弹处对话框,错误提示,显示Excel等。

该程序在Delphi4,5下编译通过,已被用在多个项目中。还被集成在笔者所写的一个小组件TDBNavigateButton中

使用实例:
DataSetToExcel( Table1, 0, False, 'Hello1.xls' );
DataSetToExcel( Table1, 2, True);

}
代码:

{-------------------------------------------------------------------------------------------------
单元:ExcelTools 
作者:Bear 
功能:保存数据集,如TTable,TQuery,TClientDataSet等为Excel文件, 
          包含标题,可以只将一部分字段导出 
          这一点通过设置DataSet中要不导出字段的Tag值大于某一个值来处理 
原理:调用 Microsoft Excel Ole对象 
调用方式: 
          Function DataSetToExcel( 
                       DataSet:TDataSet; 
                       FieldTagMax:Integer; 
                       Visible:Boolean; 
                       ExcelFileName:String='' 
                   ): Boolean;
--------------------------------------------------------------------------------------------------} 

unit ExcelTools;

interface 

uses
  classes, comctrls, stdctrls, windows, Dialogs, controls, SysUtils,
  Db,forms,DBClient,ComObj;

//把数据集导入ExcelSheet的核心函数 
function DataSetToExcelSheet 
            ( 
             DataSet     :TDataSet; 
             FieldTagMax :Integer;    
// 字段的Tag值如果大于这个值,就不导出到Excel 
             Sheet       :OleVariant 
             ): Boolean; 

//实际使用的函数,内部调用了DataSetToExcelSheet,在外面加入UI接口和错误处理 
function DataSetToExcel 
            ( 
             DataSet     :TDataSet;   
// 要转换的数据集 
             FieldTagMax :Integer;    
// 字段的Tag值如果大于这个值,就不导出到Excel 
             Visible     :Boolean;    
// 是否让做转换工作的Excel可见 
             ExcelFileName:
String=''  // Excel文件名,*.xls 
             ): Boolean; 

implementation 

function DataSetToExcelSheet(DataSet:TDataSet;FieldTagMax:Integer;Sheet:OleVariant): Boolean; 
var
  Row,Col,FieldIndex :Integer; 
  BK:TBookMark; 
begin 
  Result := False; 

  { 如果数据集未打开,就退出 } 
  
if not Dataset.Active then exit; 

  { 记下数据集当前记录位置,冻结显示控件的显示 } 
  BK:=DataSet.GetBookMark; 
  DataSet.DisableControls; 

  { 转换 : 通过循环,先转换标题,然后转换表内容 } 
  Sheet.Activate; 
  
try 
    
// 列标题 
    Row:=1; 
    Col:=1; 
    
for FieldIndex:=0 to DataSet.FieldCount-1 do 
    
begin 
      
if DataSet.Fields[FieldIndex].Tag <= FieldTagMax then 
      
begin
        Sheet.Cells(Row,Col):=DataSet.Fields[FieldIndex].DisplayLabel;
        Inc(Col);
      
end;
    
end; 
    
// 表内容
    DataSet.First; 
    
while not DataSet.Eof do
    
begin
      Row:=Row+1; 
      Col:=1; 
      
for FieldIndex:=0 to DataSet.FieldCount-1 do 
      
begin 
        
if DataSet.Fields[FieldIndex].Tag <= FieldTagMax then 
        
begin 
          Sheet.Cells(Row,Col):=DataSet.Fields[FieldIndex].AsString;
          Inc(Col); 
        
end; 
      
end; 
      DataSet.Next;

    end;

    Result := True;

  { 最后回到数据集原来的位置,恢复显示控件的同步显示 } 
  
finally 
    DataSet.GotoBookMark(BK); 
    DataSet.EnableControls; 
  
end; 

end; 

function DataSetToExcel( 
                  DataSet:TDataSet;FieldTagMax:Integer; 
                  Visible:Boolean;ExcelFileName:
String=''): Boolean; 
var 
  ExcelObj,  WorkBook, Sheet : OleVariant; 
  OldCursor : TCursor; 
  SaveDialog : TSaveDialog; 

begin 
  Result := False; 

  { 如果数据集还未打开,就退出 } 
  
if not Dataset.Active then exit; 

  { 保存当前的鼠标光标, 
    然后把鼠标光标变成等待光标,表示下面的操作可能要化点时间 } 
  OldCursor:=Screen.Cursor; 
  Screen.Cursor:=crHourGlass; 

  { 准备转换所需的Excel对象,如果失败,弹出提示 } 
  
try 
    ExcelObj := CreateOleObject(
'Excel.Sheet'); 
    ExcelObj.Application.Visible := Visible ;   
{ 让Excel可不可见 } 

    {这里没有用ExcelObj.Application.ActiveWorkBook是为了解决 
      Delphi中的OleVariant对象和实际的Excel对象的生存期冲突  } 
    WorkBook := ExcelObj.Application.Workbooks.Add ; 

    Sheet:= WorkBook.Sheets[1]; 

  except 
    MessageBox(GetActiveWindow,
'无法调用Mircorsoft Excel! '+chr(13)+chr(10)+ 
                   
'请检查是否安装了Mircorsoft Excel。','提示',MB_OK+MB_ICONINFORMATION); 
    Screen.Cursor:=OldCursor; 
    Exit; 
  
end; 

  { 如果Excel是不可见的,就要保存为文件, 
    如果没有提供文件名,就弹出文件保存对话框,让用户选择文件名 } 
  
if ( not Visible ) and ( ExcelFileName = '' ) then 
  
begin 
    SaveDialog:=TSaveDialog.Create(
Nil);
    SaveDialog.Filter := 
'Microsoft Excel 文件|*.xls'; 
    SaveDialog.Execute; 
    UpdateWindow(GetActiveWindow); 
    ExcelFileName := SaveDialog.FileName; 
    SaveDialog.Free; 
  
end; 

  {  转换Excel这时可视或不可视    }
  
if ( Visible  or ( ExcelFileName<>'' ) ) then
    Result:=DataSetToExcelSheet(DataSet,FieldTagMax,Sheet) ; 

  { 如果不可视,且转换成功,就保存到文件中 }
  
if ( ( not Visible )  and Result ) then
  
begin 
    WorkBook.SaveAs(FileName:=ExcelFileName);
    WorkBook.Close;
    Application.MessageBox(
' 数据已经成功导出到Excel中!','导出成功',MB_OK+MB_ICONINFORMATION);
  
end;

  { 所有工作已完成,把鼠标光标变为原来的样子 }
  Screen.Cursor:=OldCursor;

end; 

end.

抱歉!评论已关闭.