亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Delphi > 正文

Delphi與Excel的親密接觸

2019-11-18 18:40:45
字體:
來源:轉載
供稿:網友
Delphi與Excel的親密接觸 [王安鵬(anpengwang@263.net) 2002/4/14] 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。此外,命名的區域應使用絕對引用方式,即加上“$”符號。一旦命名了一個區域,就可以使用這個名稱來引用它,下面的一行代碼使通訊錄內容以粗體顯示: 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; //橫向打?。╨andscape)=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的親密接觸 [王安鵬(anpengwang@263.net) 2002/4/14] 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; //橫向打?。╨andscape)=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; 這里沒有采用通常的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中捕獲控制臺程序的輸出

下一篇:獲取其他線程的光標句柄[DELPHI]

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
學習交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網友關注

亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
91成人在线观看国产| 亚洲精品久久久久中文字幕二区| 国产精品av在线| 日韩电影在线观看免费| 成人网址在线观看| 色偷偷噜噜噜亚洲男人| 国产va免费精品高清在线| 色综合久久久888| 日韩在线免费高清视频| www.99久久热国产日韩欧美.com| 精品无人区太爽高潮在线播放| 亚洲高清不卡av| 日韩资源在线观看| 91精品国产99久久久久久| 日韩av成人在线| 国产极品精品在线观看| 欧美激情精品久久久久久蜜臀| 欧美激情中文网| 欧美日韩第一页| 91久久精品国产91久久性色| 久久九九有精品国产23| 欧美色道久久88综合亚洲精品| 欧美成人黄色小视频| 亚洲视频综合网| 中文字幕亚洲综合久久| 欧美日韩国产精品| 日韩成人小视频| 欧美一区二区三区精品电影| 欧美性生活大片免费观看网址| 久久久久久91香蕉国产| 亚洲国产精品久久久久| 成人网欧美在线视频| 国产中文日韩欧美| 91超碰中文字幕久久精品| 亚洲第一中文字幕在线观看| 国产一区二区欧美日韩| 欧美激情性做爰免费视频| 中文字幕欧美亚洲| 亚洲国产天堂网精品网站| 日本a级片电影一区二区| 成人福利免费观看| 国产精品日日摸夜夜添夜夜av| 国产一区二区激情| 久久免费精品日本久久中文字幕| 欧美日韩精品在线| 久久久久久免费精品| 91精品视频在线看| 国产69精品久久久久9999| 亚洲欧美日韩精品久久亚洲区| 成年人精品视频| 国产精品麻豆va在线播放| 精品女同一区二区三区在线播放| 久久久久久噜噜噜久久久精品| 欧美有码在线观看| 日韩美女av在线| 亚洲精品99999| 永久免费精品影视网站| 岛国av午夜精品| 亚洲最大av网| 伊人久久五月天| 国内外成人免费激情在线视频网站| 一本一本久久a久久精品牛牛影视| 91精品国产乱码久久久久久久久| 日韩亚洲综合在线| 成人日韩在线电影| 麻豆乱码国产一区二区三区| 亚洲久久久久久久久久| 欧美午夜视频在线观看| 中文日韩电影网站| 欧美亚洲成人网| 日韩欧美一区二区三区| 亚洲欧洲一区二区三区久久| 97人人爽人人喊人人模波多| 日韩精品免费看| 欧美亚洲成人xxx| 精品国产成人在线| 精品精品国产国产自在线| 国产日韩av在线播放| 欧美高清一级大片| 成人网欧美在线视频| 成人午夜在线观看| 国产精品久久久久久一区二区| 精品久久久久久久久久久久| 欧美性xxxx极品高清hd直播| 国产福利成人在线| 日韩欧美在线观看| 中文字幕国产精品久久| 91午夜理伦私人影院| 欧美性猛交xxxx久久久| 国内成人精品视频| 精品在线欧美视频| 久久精品国产精品| 欧美成人一区二区三区电影| 国外成人免费在线播放| 日韩在线观看免费全集电视剧网站| 亚洲国产成人在线播放| 亚洲精品久久久久中文字幕二区| 超碰91人人草人人干| 亚洲电影免费观看高清完整版在线| 日韩免费av一区二区| 视频在线观看一区二区| 欧美大尺度激情区在线播放| 91中文在线视频| 国产精品高潮视频| 日本久久中文字幕| 国产小视频91| 成人国内精品久久久久一区| 78m国产成人精品视频| 欧美激情综合色综合啪啪五月| 成人免费xxxxx在线观看| 91久久在线视频| 欧美激情一级二级| 成人午夜激情免费视频| 国产脚交av在线一区二区| 欧美在线观看网址综合| 亚洲综合在线中文字幕| 亚洲а∨天堂久久精品9966| 日韩精品极品在线观看播放免费视频| 成人中心免费视频| 国产精品久久久久久久久久尿| 欧美日韩国产123| 国产成人亚洲精品| 不卡毛片在线看| 久久视频在线视频| 亚洲人成啪啪网站| 欧美大人香蕉在线| 亚洲欧美日本伦理| 国产一区二区三区毛片| 热99精品只有里视频精品| 欧美精品在线视频观看| 日本一区二三区好的精华液| 亚洲日本成人女熟在线观看| 欧美激情欧美激情| 亚洲欧美日韩天堂一区二区| 久久精品青青大伊人av| 成人性生交大片免费观看嘿嘿视频| 亚洲白虎美女被爆操| 久久久久五月天| 亚洲精品99久久久久中文字幕| 亚洲精品自产拍| 精品亚洲国产视频| 麻豆国产va免费精品高清在线| 国产一区二区三区丝袜| 欧美激情亚洲一区| 久久久久国产精品www| 国产精品91久久久| 国产在线98福利播放视频| 中文字幕9999| 欧美巨乳在线观看| 亚洲精品视频免费| 日本成人免费在线| 色一情一乱一区二区| 国产mv久久久| 国产精品久久久av| 在线免费看av不卡| 中文字幕欧美精品在线| 九九九久久久久久| 日韩人体视频一二区| 亚洲国产欧美精品| 一区二区三区在线播放欧美| 日韩免费观看视频| 高清欧美性猛交xxxx| 欧美亚洲另类激情另类| 日韩av在线免费观看|