我的grid列数是不固定的,要导出到excel,求代码。谢谢!
解决方案 »
- 设计好的RzGroupBar如何调整RzGroup顺序?
- 程序中如何读取某指定文件夹中已经选中的一批文件的名字?
- 如何同步程序与音频终端的Mp3播放(硬件无反馈)
- 不明白,下面过程中"i<"是啥意思
- 为什么我的线程执行起来那么困难 甚至象死机了一样啊:
- 有关sql连接的问题
- 可怜可怜我吧!如何改变TEdit或TRichEdit里面所选定的文字的字体。。
- qreport上为什么不会自动分页啊
- 急,请问如何为设计的程序编写序列号?
- 在QuickRep中如何取得打印机设定的纸张
- Delphi下如何实现如同VB中On Error Resume Next的功能?
- 难道大家用的fastreport3.0(3.03)都已经注册过的吗?还有不打印背景图怎么设置了?
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;
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。此外,命名的区域应使用绝对引用方式,即加上“$”符号。一旦命名了一个区域,就可以使用这个名称来引用它,下面的一行代码使通讯录内容以粗体显示: 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;
有BCB的 你改动一下就行
下面给出用到的方法:
//注意:下面的方法必须包含 ComObj, Excel97 单元
//-----------------------------------------------------------
// if toExcel = false, export dbgrid contents to the Clipboard
// if toExcel = true, export dbgrid to Microsoft Excel
procedure ExportDBGrid(toExcel: Boolean);
var
bm: TBook;
col, row: Integer;
sline: String;
mem: TMemo;
ExcelApp: Variant;
begin
Screen.Cursor := crHourglass;
DBGrid1.DataSource.DataSet.DisableControls;
bm := DBGrid1.DataSource.DataSet.GetBook;
DBGrid1.DataSource.DataSet.First;
// create the Excel object
if toExcel then
begin
ExcelApp := CreateOleObject('Excel.Application');
ExcelApp.WorkBooks.Add(xlWBatWorkSheet);
ExcelApp.WorkBooks[1].WorkSheets[1].Name := 'Grid Data';
end;
// First we send the data to a memo
// works faster than doing it directly to Excel
mem := TMemo.Create(Self);
mem.Visible := false;
mem.Parent := MainForm;
mem.Clear;
sline := '';
// add the info for the column names
for col := 0 to DBGrid1.FieldCount-1 do
sline := sline + DBGrid1.Fields[col].DisplayLabel + #9;
mem.Lines.Add(sline);
// get the data into the memo
for row := 0 to DBGrid1.DataSource.DataSet.RecordCount-1 do
begin
sline := '';
for col := 0 to DBGrid1.FieldCount-1 do
sline := sline + DBGrid1.Fields[col].AsString + #9;
mem.Lines.Add(sline);
DBGrid1.DataSource.DataSet.Next;
end;
// we copy the data to the clipboard
mem.SelectAll;
mem.CopyToClipboard;
// if needed, send it to Excel
// if not, we already have it in the clipboard
if toExcel then
begin
ExcelApp.Workbooks[1].WorkSheets['Grid Data'].Paste;
ExcelApp.Visible := true;
end;
FreeAndNil(mem);
// FreeAndNil(ExcelApp);
DBGrid1.DataSource.DataSet.GotoBook(bm);
DBGrid1.DataSource.DataSet.FreeBook(bm);
DBGrid1.DataSource.DataSet.EnableControls;
Screen.Cursor := crDefault;
end;
procedure DbgridToExcel(Title: String; DbGrid: TDbGrid; Total: Boolean);
var
ExcelApp, WorkBook: Variant;
i, j: Integer;
Row, Col: Integer;
FieldName: string;
DataSet: TDataSet;
S: String;
begin
// 数据发送到 Excel
try
ExcelApp := CreateOleObject('Excel.Application');
WorkBook := CreateOleObject('Excel.Sheet');
except
Application.MessageBox('你的机器里未安装Microsoft Excel. ', '', 32);
Exit;
end; Application.ProcessMessages;
WorkBook := ExcelApp.WorkBooks.Add;
Col := 1;
ExcelApp.Cells(2, Col) := Title;
Row := 1;
DataSet := DBGrid.DataSource.DataSet;
for I := 0 to DBGrid.Columns.Count - 1 do
begin
if DBGrid.Columns[I].Visible then
begin
FieldName := DBGrid.Columns[I].Title.Caption;
ExcelApp.Cells(Row, Col) := FieldName;
Col := Col + 1;
end;
end; Row := Row + 1; DataSet.First;
while not DataSet.Eof do
begin
Col := 1;
for J := 0 to DBGrid.Columns.Count - 1 do
begin
FieldName := DBGrid.Columns[J].FieldName;
ExcelApp.Cells(Row, Col) := ' ' + DataSet.FieldByName(FieldName).AsString + ' ';
Col := Col + 1;
end;
Row := Row + 1;
DataSet.Next;
end; if Total then
begin
Col := 1;
for J := 0 to DBGrid.Columns.Count - 1 do
begin
S := Char(64 + ((J+1) mod 26));
if (J+1) > 26 then
begin
S := Char(65+(((J+1)-26) div 26)) + S;
end;
if J = 0 then
begin
ExcelApp.Cells(Row, Col) := '合计';
end
else if DBGrid.Columns[J].Field.DataType in [ftInteger, ftSmallint, ftFloat, ftBCD] then
begin
FieldName := DBGrid.Columns[J].FieldName;
ExcelApp.Cells(Row, Col) := '=SUM('+S+'4:'+S+IntToStr(Row-1)+')';
end;
Col := Col + 1;
end;
end;
ExcelApp.Visible := True;
end;