在开发
数据库应用
程序中, 经常要将类型相同的数据导出来,放到Excel文件中,利用Excel强大的编辑功能,对数据作进一步的加工处理。这有许多的方法,我们可以使用OLE技 术,在Delphi中创建一个自动化对象,通过该对象来传送数据。也可以使用ADO,通过与Excel数据存储建立连接,使用ADO这种独立于
数据库后端的技术来导出数据集的数据。
可这两种技术都有一个共同的缺点,那就是慢,数据量少还好,用户不会有太多的感觉,可一旦数据量大,比如,超过1千条,速度就让人难以忍受了,那么有 没有更好的办法,既可以快速地导出数据,又不用安装附加的软件。也许好多人都想到了剪贴板的方式,这种方式速度是快,可也有不好的一面,那就是数据量大占 用内存也大,并且在Excel中调用PASTE方法时,需要锁定输入,这使用起来,就有点不方便了
这里我为大家介始一种比较好的方法,使用文件流的方式,通过TfileStream直接写入Excel文件。我写了一个函数,通过它可将数据集中的数据直接导入到Excel文件中。我测试了一下,1M的数据,不到十秒就完成了。附源 程序。
首先在你的 程序中定义以下几个数组:
接着调用下面的函数。
以上 代码,在DELPHI6中通过测试!
可这两种技术都有一个共同的缺点,那就是慢,数据量少还好,用户不会有太多的感觉,可一旦数据量大,比如,超过1千条,速度就让人难以忍受了,那么有 没有更好的办法,既可以快速地导出数据,又不用安装附加的软件。也许好多人都想到了剪贴板的方式,这种方式速度是快,可也有不好的一面,那就是数据量大占 用内存也大,并且在Excel中调用PASTE方法时,需要锁定输入,这使用起来,就有点不方便了
这里我为大家介始一种比较好的方法,使用文件流的方式,通过TfileStream直接写入Excel文件。我写了一个函数,通过它可将数据集中的数据直接导入到Excel文件中。我测试了一下,1M的数据,不到十秒就完成了。附源 程序。
首先在你的 程序中定义以下几个数组:
arXlsBegin: array[0..5] of Word = ($809, 8, 0, $10, 0, 0); arXlsEnd: array[0..1] of Word = ($0A, 00); arXlsString: array[0..5] of Word = ($204, 0, 0, 0, 0, 0); arXlsNumber: array[0..4] of Word = ($203, 14, 0, 0, 0); arXlsInteger: array[0..4] of Word = ($27E, 10, 0, 0, 0); arXlsBlank: array[0..4] of Word = ($201, 6, 0, 0, $17); |
接着调用下面的函数。
Procedure ExportExcelFile(FileName: string; bWriteTitle: Boolean; aDataSet: TDataSet); var i, j: integer; Col, row: word; ABookMark: TBookMark; aFileStream: TFileStream; procedure incColRow; //增加行列号 begin if Col = ADataSet.FieldCount - 1 then begin Inc(Row); Col :=0; end else Inc(Col); end; procedure WriteStringCell(AValue: string);//写字符串数据 var L: Word; begin L := Length(AValue); arXlsString[1] := 8 + L; arXlsString[2] := Row; arXlsString[3] := Col; arXlsString[5] := L; aFileStream.WriteBuffer(arXlsString, SizeOf(arXlsString)); aFileStream.WriteBuffer(Pointer(AValue)^, L); IncColRow; end; procedure WriteIntegerCell(AValue: integer);//写整数 var V: Integer; begin arXlsInteger[2] := Row; arXlsInteger[3] := Col; aFileStream.WriteBuffer(arXlsInteger, SizeOf(arXlsInteger)); V := (AValue shl 2) or 2; aFileStream.WriteBuffer(V, 4); IncColRow; end; procedure WriteFloatCell(AValue: double);//写浮点数 begin arXlsNumber[2] := Row; arXlsNumber[3] := Col; aFileStream.WriteBuffer(arXlsNumber, SizeOf(arXlsNumber)); aFileStream.WriteBuffer(AValue, 8); IncColRow; end; begin if FileExists(FileName) then DeleteFile(FileName); //文件存在,先删除 aFileStream := TFileStream.Create(FileName, fmCreate); Try //写文件头 aFileStream.WriteBuffer(arXlsBegin, SizeOf(arXlsBegin)); //写列头 Col := 0; Row := 0; if bWriteTitle then begin for i := 0 to aDataSet.FieldCount - 1 do WriteStringCell(aDataSet.Fields[i].FieldName); end; //写数据集中的数据 aDataSet.DisableControls; ABookMark := aDataSet.GetBookmark; aDataSet.First; while not aDataSet.Eof do begin for i := 0 to aDataSet.FieldCount - 1 do case ADataSet.Fields[i].DataType of ftSmallint, ftInteger, ftWord, ftAutoInc, ftBytes: WriteIntegerCell(aDataSet.Fields[i].AsInteger); ftFloat, ftCurrency, ftBCD: WriteFloatCell(aDataSet.Fields[i].AsFloat) else WriteStringCell(aDataSet.Fields[i].AsString); end; aDataSet.Next; end; //写文件尾 AFileStream.WriteBuffer(arXlsEnd, SizeOf(arXlsEnd)); if ADataSet.BookmarkValid(ABookMark) then aDataSet.GotoBookmark(ABookMark); Finally AFileStream.Free; ADataSet.EnableControls; end; end; |
以上 代码,在DELPHI6中通过测试!
在delphi中调用excel有四种方式,我们选取其中的一种用OleObject来装载excel工作表的方式来谈delphi控制excel的重要属性和方法。
首先给出通过OLE创建的一些主要代码步进行简单说明:
创建OLE对象:
Var olecon: TOleContainer;
Olecon:= TOleContainer.Create(self);
Olecon.oleobject:= Olecon.CreateObject('excel.sheet',false);
或选择导入一个excel文件来创建OLE对象:
Olecon.oleobject:= Olecon.CreateObjectFromFile(xlsname,false);
最好隐藏excel的几个工具条,这样就好象是嵌在你的程序中的一个表而已了:
Olecon.OleObject.application.CommandBars['Standard'].Visible:=false;
Olecon.OleObject.application.CommandBars['Formatting'].Visible:=false;
Olecon.OleObject.application.CommandBars['Reviewing'].Visible:=false;
然后显示并激活excel表,对TOleContainer定义的对象:
Olecon.show;
Olecon.doverb(0);
这样基本可以了,但TOleContainer有个不好的地方,就是当你一点击其它控件是就它就失去焦点,然后就自动退出,其实并没有真的退出,只是需要 你再次激活它而已,关键是当它失去焦点的时候就excel对象就不见了,可以用Timage控件把TOleContainer所在的地方有EXCEL时候 的区域图片截下来骗骗用户,我们这里主要不是讲这个,就不详述了。
下面我们就开始讲Excel_TLB中的接口的常用属性和方法,主要是针对导出和设定报表格式的一些接口元素。
单元格的读写属性:
olecon.OleObject.application.cells.item[1,1];
olecon.OleObject.application.cells(1,1);
olecon.OleObject.application.cells[1,1].Value;
上面三种都可以对工作表的‘A1'单元进行读写。
在delphi中对单元格(集),区域,工作表等所有对象的操作都是要Variant来实现的。
自己的程序中选定区域赋给Range:
Var range,sheet:Variant;
Range:= olecon.OleObject.application.Range['A1:C3'];
或者:
Sheet:= olecon.OleObject.application.Activesheet;
Range:= olecon.OleObject.application.Range[sheet.cells[1,1],sheet.cells[3,3]];
对上面的Range合并单元格:
Range.merge;
Range. FormulaR1C1:='合并区';//合并后写入文本
注意以后要读合并的单元格里面的文本就是读合并区域的左上角的那个单元格的文本
在excel表中选定区域赋给range:
range:=excel_grid1.OleObject.application.selection;
拆分单元格:
Range.unmerge;
合并后设定单元格(集)的格式:
Range.HorizontalAlignment:= xlCenter;// 文本水平居中方式
Range.VerticalAlignment:= xlCenter//文本垂直居中方式
Range.WrapText:=true;//文本自动换行
Range.Borders.LineStyle:=1//加边框
Range.Interior.ColorIndex:=39;//填充颜色为淡紫色
Range.Font.name:='隶书';//字体
Range.Font.Color:=clBlue;//字体颜色
常用格式也就这些,以上这些对于单个单元格也适用。
在excel表中寻找前后上下的单元格:
Var u1,u2,u3,u4,u5:Variant;
U1:=olecon.oleobject.application.activecell;//获取当前格;
U2:=u1.previous;//非特殊情况就是u1左边的一格;
U3:=ui.next;//非特殊情况就是u2右边的一格;
U4:=olecon.oleobject.application.cells[u1.cells.row-1,u1.cells.column];//非特殊情况为上面一格
U5:=olecon.oleobject.application.cells[u1.cells.row+1,u1.cells.column];//非特殊情况为下面一格
删除和插入一行和一列:
Olecon.oleobject.application.rows[2].delete;
Olecon.oleobject.application.columns[2].delete;
Olecon.oleobject.application.rows[2].insert;
Olecon.oleobject.application.columns[2].insert;
复制指定区域:
Olecon.oleobject.application.range['A1:C3'].copy;
从指定单元格开始粘贴:
Olecon.oleobject.application.range['A4'].PasteSpecial;
常用的就这些了,对delphi中server面板下的EXEL控件和创建EXCEL.Application COM对象的方式都适用
首先给出通过OLE创建的一些主要代码步进行简单说明:
创建OLE对象:
Var olecon: TOleContainer;
Olecon:= TOleContainer.Create(self);
Olecon.oleobject:= Olecon.CreateObject('excel.sheet',false);
或选择导入一个excel文件来创建OLE对象:
Olecon.oleobject:= Olecon.CreateObjectFromFile(xlsname,false);
最好隐藏excel的几个工具条,这样就好象是嵌在你的程序中的一个表而已了:
Olecon.OleObject.application.CommandBars['Standard'].Visible:=false;
Olecon.OleObject.application.CommandBars['Formatting'].Visible:=false;
Olecon.OleObject.application.CommandBars['Reviewing'].Visible:=false;
然后显示并激活excel表,对TOleContainer定义的对象:
Olecon.show;
Olecon.doverb(0);
这样基本可以了,但TOleContainer有个不好的地方,就是当你一点击其它控件是就它就失去焦点,然后就自动退出,其实并没有真的退出,只是需要 你再次激活它而已,关键是当它失去焦点的时候就excel对象就不见了,可以用Timage控件把TOleContainer所在的地方有EXCEL时候 的区域图片截下来骗骗用户,我们这里主要不是讲这个,就不详述了。
下面我们就开始讲Excel_TLB中的接口的常用属性和方法,主要是针对导出和设定报表格式的一些接口元素。
单元格的读写属性:
olecon.OleObject.application.cells.item[1,1];
olecon.OleObject.application.cells(1,1);
olecon.OleObject.application.cells[1,1].Value;
上面三种都可以对工作表的‘A1'单元进行读写。
在delphi中对单元格(集),区域,工作表等所有对象的操作都是要Variant来实现的。
自己的程序中选定区域赋给Range:
Var range,sheet:Variant;
Range:= olecon.OleObject.application.Range['A1:C3'];
或者:
Sheet:= olecon.OleObject.application.Activesheet;
Range:= olecon.OleObject.application.Range[sheet.cells[1,1],sheet.cells[3,3]];
对上面的Range合并单元格:
Range.merge;
Range. FormulaR1C1:='合并区';//合并后写入文本
注意以后要读合并的单元格里面的文本就是读合并区域的左上角的那个单元格的文本
在excel表中选定区域赋给range:
range:=excel_grid1.OleObject.application.selection;
拆分单元格:
Range.unmerge;
合并后设定单元格(集)的格式:
Range.HorizontalAlignment:= xlCenter;// 文本水平居中方式
Range.VerticalAlignment:= xlCenter//文本垂直居中方式
Range.WrapText:=true;//文本自动换行
Range.Borders.LineStyle:=1//加边框
Range.Interior.ColorIndex:=39;//填充颜色为淡紫色
Range.Font.name:='隶书';//字体
Range.Font.Color:=clBlue;//字体颜色
常用格式也就这些,以上这些对于单个单元格也适用。
在excel表中寻找前后上下的单元格:
Var u1,u2,u3,u4,u5:Variant;
U1:=olecon.oleobject.application.activecell;//获取当前格;
U2:=u1.previous;//非特殊情况就是u1左边的一格;
U3:=ui.next;//非特殊情况就是u2右边的一格;
U4:=olecon.oleobject.application.cells[u1.cells.row-1,u1.cells.column];//非特殊情况为上面一格
U5:=olecon.oleobject.application.cells[u1.cells.row+1,u1.cells.column];//非特殊情况为下面一格
删除和插入一行和一列:
Olecon.oleobject.application.rows[2].delete;
Olecon.oleobject.application.columns[2].delete;
Olecon.oleobject.application.rows[2].insert;
Olecon.oleobject.application.columns[2].insert;
复制指定区域:
Olecon.oleobject.application.range['A1:C3'].copy;
从指定单元格开始粘贴:
Olecon.oleobject.application.range['A4'].PasteSpecial;
常用的就这些了,对delphi中server面板下的EXEL控件和创建EXCEL.Application COM对象的方式都适用