Enger Kontakt zwischen Delphi und Excel [Wang Anpeng ([email protected]) 14.04.2002] Als hervorragendes RAD ist die leistungsstarke Datenbankfunktion von Delphi eine der wichtigsten Funktionen, das schwierig zu bedienende QuickReport-Steuerelement jedoch oft nicht Erfüllen Sie die Anforderungen an die Datenbankberichterstattung. Wenn Ihr Bericht sehr komplex ist oder Flexibilität bei Formatänderungen erfordert, ist die Verwendung von Excel als Berichtsserver eine gute Wahl. Die von Delphi ab Version 5 bereitgestellte Excel-Komponente vereinfacht die Anwendung der OLE-Automatisierungstechnologie erheblich. Allerdings waren die fehlenden Hilfedateien schon immer der am meisten kritisierte Aspekt von Delphi, und diese neuen Komponenten bilden da keine Ausnahme. In diesem Artikel wird versucht, dies detaillierter vorzustellen. Das Objektmodell von Excel ist eine baumartige hierarchische Struktur. Das Arbeitsblatt, das hauptsächlich für den Datenaustausch verwendet wird, ist das Attributobjekt der Arbeitsmappe Weitere Informationen finden Sie in der MSOffice Excel VBA-Hilfedatei. Um Excel in Delphi zu steuern, müssen Sie zunächst eine Verbindung mit dem Serverprogramm herstellen, die Arbeitsmappe öffnen, dann Daten mit dem Zielarbeitsblatt austauschen und schließlich die Verbindung trennen. Öffnen Sie die Excel-Arbeitsmappe. Unser Beispiel beginnt mit einem Hauptformular mit einem TStringGrid (natürlich müssen einige Daten ausgefüllt werden) und zwei Schaltflächen. Ziehen Sie ein TExcelapplication-Steuerelement aus der Registerkarte „Server“ des Bedienfelds und platzieren Sie es auf dem Formular. Setzen Sie ConnectKind zunächst auf ckRunningOrNew. Das heißt, wenn die laufende Excel-Instanz erkannt werden kann, stellen Sie Kontakt mit ihr her, andernfalls starten Sie Excel. Wenn Sie möchten, dass das Programm außerdem sofort nach der Ausführung Kontakt zum Serverprogramm herstellt, können Sie die Eigenschaft AutoConnect auf True setzen. Um den Kontakt zu Excel herzustellen, ist nur eine Anweisung erforderlich: Excel Connect; Excel . ActiveWorkbook); ExcelWorksheet1.ConnectTo(Excel . ActiveSheet as _Worksheet2.ConnectTo(Excel . Worksheets.Item['Sheet2']); _Worksheet); Es ist zu beachten, dass vor der Verwendung der ConnectTo-Methode die entsprechende Arbeitsmappe oder das entsprechende Arbeitsblatt geöffnet werden muss. Darüber hinaus bringen diese Steuerelemente in den meisten Fällen keinen zusätzlichen Komfort, daher ist es am besten, nur eine TExcelApplication zu verwenden. Sobald der Kontakt mit dem Excel-Server hergestellt ist, kann eine neue Arbeitsmappe erstellt werden: var LCID : Integer; ... LCID := GetUserDefaultLCID(); Funktion Der erste Parameter wird verwendet, um die für die neue Arbeitsmappe verwendete Vorlage zu definieren. Sie können xlWBATChart, xlWBATExcel4IntlMacroSheet, verwenden. xlWBATExcel4MacroSheet- oder xlWBATWorksheet-Konstante, oder es kann der Name einer vorhandenen XLS-Datei sein. Das EmptyParam ist hier die Variants-Einheit und die definierte Variable, was bedeutet, dass die standardmäßige universelle Vorlage zum Erstellen einer neuen Arbeitsmappe verwendet wird. Wenn Sie ein vorhandenes XLS-Dokument öffnen, sollten Sie den zu öffnenden Dateinamen als ersten Parameter an die Open-Funktion übergeben: wkBook:=Excel.WorkBooks.Open(edtDesFile.text,EmptyParam,EmptyParam, EmptyParam,EmptyParam,EmptyParam,EmptyParam , EmptyParam,EmptyParam,EmptyParam,EmptyParam, EmptyParam,EmptyParam,LCID); Sie müssen wissen, dass alle Datenoperationen hauptsächlich für das aktive Arbeitsblatt gelten. Die folgende Anweisung verwendet eine _WorkSheet-Variable, um die aktuell aktive Zelle darzustellen. Wenn Sie den Namen des Arbeitsblatts kennen, kann die Indexnummer durch den Arbeitsblattnamen ersetzt werden: wkSheet:=wkBook.Sheets[1] as _WorkSheet; Nach Abschluss des Datenaustauschs müssen Sie die Arbeitsmappe speichern: Excel.ActiveWorkBook.SaveAs ('MyOutput', EmptyParam ,EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, LCID); oder: Excel.ActiveWorkBook.Save(LCID); Schließen Sie schließlich die Arbeitsmappe und trennen Sie die Verbindung zu Excel: wkBook.Close(True, SaveAsName, LCID); ; Die Close-Methode enthält hier die Speicherfunktion. Der erste Parameter gibt an, ob die Änderungen gespeichert werden sollen, bevor die Arbeitsmappe geschlossen wird. Der dritte Parameter wird für die Verarbeitung des Dokuments verwendet. Die zweite Zeile fordert zum Beenden von Excel auf. Datenaustausch mit dem Arbeitsblatt Die Eingabedaten werden für eine bestimmte Zelle oder einen bestimmten Bereich des aktiven Arbeitsblatts ausgeführt. Bereich und Zellen sind beide Objekteigenschaften des Arbeitsblatts. „Cells“ ist eine Sammlung von Zellen. Wenn kein bestimmter Speicherort angegeben ist, kann sie alle Zellen im gesamten Arbeitsblatt darstellen. Im Allgemeinen wird sie jedoch verwendet, um auf eine bestimmte Zelle zu verweisen. stellt die aktuellste Zelle in der oberen linken Ecke dar. Beachten Sie, dass „Item“ die Standardeigenschaft von „Cells“ in VBA ist und weggelassen werden kann, in Delphi gibt es diese Funktion jedoch nicht. Um einer Zelle einen Wert zuzuweisen, müssen Sie auf deren Value-Eigenschaft verweisen. Es versteht sich von selbst, dass diese Eigenschaft eine Variant-Variable ist, zum Beispiel: wkSheet.Cells.Item[1, 1].Value := 'Address Book'; Natürlich können Sie einer Zelle auch einen Wert zuweisen: var AFormula:String …… AFormula:='=Rand()'; wkSheet.Range['F3','G6'].Value:=AFormula; Die obige Methode ist sehr direkt und einfach, aber sie ist sehr langsam und nicht für große Berichte geeignet. Können also alle Daten der Reihe nach nach Excel übertragen werden? Wir können Range verwenden. Wenn wir es mit der Maus herausziehen, ist es normalerweise ein rechteckiger Bereich. Geben Sie einfach die Positionen seiner oberen linken Ecke und seiner unteren rechten Ecke an, z. B. Range[ 'C3 ','J42']. Hier gibt es ein kleines Problem, denn wenn die Daten 26 Spalten überschreiten (z. B. 100 Spalten) oder der Zielbereich im laufenden Betrieb bestimmt werden muss, ist es schwieriger, Zeichennamen zum Markieren von Zellen zu verwenden. Denken Sie daran, dass wir natürlich auch Zellen verwenden können, da „C3“ die Bezeichnung der Zelle ist, z. B. Range[Cells.Item[1,1], Cells.Item[100,100]]. Es ist denkbar, dass der Wert von Range ein Array sein sollte, aber Sie dürfen Array in Delphi nicht verwenden, um ihm einen Wert zuzuweisen! Denken Sie daran, dass in Delphi der Wert eines Excel-Objekts immer vom Typ Variant ist. var Datas: Variant; Ir, ic: Integer; …… Datas:= varArrayCreate([1,ir,1,ic],varVariant); //Hier ein 100*100 dynamisches Array erstellen… //Werte zuweisen Array-Elemente hier mit wkSheet do Range[cells.Item[3,1],cells.Item[ir+2,ic]].Value:=Datas; Es ist zu beachten, dass sowohl das Arbeitsblatt als auch der Bereich über die Cells-Eigenschaft verfügen. Aus Gründen der Übersichtlichkeit wird hier die with-Anweisung verwendet. Darüber hinaus ist Range gerichtet. Ein mit VarArrayCreate erstelltes eindimensionales Array kann nur einem einzeiligen Range zugewiesen werden. Wenn Sie einen Wert für einen einspaltigen Range definieren möchten, müssen Sie z. B. ein zweidimensionales Array verwenden Beispiel: Datas:=VarArrayCreate([1,100,1 ,1], varVariant); //Erstelle ein 100*1 dynamisches Array. Übrigens gibt Cells.Item[] tatsächlich ein Range-Objekt zurück. Das Abrufen von Daten aus dem Arbeitsblatt ist im Grunde der umgekehrte Vorgang zum Schreiben von Daten. Es muss darauf geachtet werden, wie der Datenbereich des Arbeitsblatts bestimmt wird: var ir, ic : Integer; …… wkSheet.Cells.SpecialCells(xlCellTypeLastCell,EmptyParam ).Activate ; ir := Excel.ActiveCell.Row; ic := Excel.ActiveCell.Column; Die spezielle Zellfunktion SpecialCells wird hier geschickt eingesetzt, um die letzte Zelle mit Daten zu erhalten. Datenbearbeitung Nachfolgend finden Sie zwei Beispiele für die Datenbearbeitung. var DestRange: OleVariant; begin DestRange := Excel.Range['C1', 'D4']; Copy(DestRange); Wenn Sie der Copy-Funktion einen leeren Parameter übergeben, werden die Daten in diesem Bereich in die Zwischenablage kopiert und können später mit der Paste-Methode an anderen Stellen eingefügt werden. var WS: _Worksheet; …… Excel.Range['A1', 'B4'].Copy(EmptyParam); //Daten in ein Arbeitsblatt in die Zwischenablage kopieren WS := Excel.Activesheet as _Worksheet WS; .Range['C1', 'D4'].Select; WS.Paste(EmptyParam, EmptyParam, lcid); //Fügen Sie den Inhalt der Zwischenablage in ein neues Arbeitsblatt ein. Formateinstellungen Wählen Sie Excel als Berichtsserver, hauptsächlich wegen seiner leistungsstarken Formatierungsfunktionen. Wir führen zunächst die Zellen mit dem Titel „Adressbuch“ zusammen und zeigen ihn in der Mitte an. Anschließend ändern wir die Schriftart in „offizielle Schrift“ mit 18 Punkt Fettschrift: mit wkSheet.Range['A1','D1'],Font do begin Merge(True); //Zellen zusammenführen HorizontalAlignment:= xlCenter; Name:='official script'; Wenn der Zelleninhalt lang ist, wird ein Teil des Inhalts nicht angezeigt. Die übliche Vorgehensweise besteht darin, auf den rechten Rand des ausgewählten Bereichs zu doppelklicken, damit sich die Breite jeder Spalte automatisch an die Länge des Inhalts anpasst. In Delphi können adaptive Spaltenbreite und Zeilenhöhe auch über die AutoFit-Methode erreicht werden. Es ist zu beachten, dass diese Methode nur für die gesamte Zeile und gesamte Spalte verwendet werden kann, andernfalls wird ein Fehler angezeigt, dass die Ausführung der OLE-Methode verweigert wird: wkSheet.Columns.EntireColumn.AutoFit; Berichte im chinesischen Stil erfordern normalerweise obere und untere begrenzte Tabellenzeilen, und Sie können die Borders-Sammlungseigenschaft verwenden. Es ist zu beachten, dass Sammlungsobjekte in VBA normalerweise über eine Standard-Item-Eigenschaft verfügen, die in Delphi nicht weggelassen werden kann. Die Weight-Eigenschaft wird verwendet, um die Dicke von Tabellenlinien zu definieren: mit Aname.RefersToRange,Borders do begin HorizontalAlignment:= xlRight Item[xlEdgeTop].Weight:=xlMedium; .Gewicht: =xlThin; item[xlInsideVertical].Weight:=xlThin; Seiteneinrichtung und Druckseiteneinrichtung werden über die Objekteigenschaft PageSetUp des Arbeitsblatts festgelegt. In Excel VBA sind mehr als 40 Papierkonstanten voreingestellt. Es ist zu beachten, dass einige Drucker nur einige der Papiertypen unterstützen. Das Attribut „Ausrichtung“ dient zur Steuerung der Druckrichtung und die Konstante „Landschaft = 2“ gibt horizontales Drucken an. Die booleschen Eigenschaften CenterHorizontally und CenterVertically werden verwendet, um zu bestimmen, ob der gedruckte Inhalt horizontal und vertikal zentriert ist. with wkSheet.PageSetUp do begin PaperSize:=xlPaperA4; //Papiertyp A4 PRintTitleRows := 'A1:D1'; //Repeat this row/page LeftMargin:=18; //0.25" Left Margin RightMargin:=18; // 0,25" variiert zwischen den Druckern. TopMargin:=36; //0,5" BottomMargin:=36; //0.5" CenterHorizontally:=True; Orientation:=1; //Horizontaler Druck (Querformat)=2, Hochformat=1 end; Um einen Bericht zu drucken, können Sie die PrintOut-Methode des Arbeitsblatts aufrufen. Diese von VBA definierte Methode hat 8 optionale Parameter. Die ersten beiden werden verwendet, um die Start- und Endseiten sowie die Anzahl der zu druckenden Kopien im dritten Format anzugeben. In Delphi wird jedoch am Ende ein LCID-Parameter hinzugefügt, und EmptyParam kann nicht verwendet werden für diesen Parameter. Ebenso verfügt die Druckvorschau-Methode PrintPreview in VBA über keine Parameter, erfordert jedoch beim Aufruf in Delphi zwei Parameter. // wkBook.PrintPreview(True,LCID); //für die Vorschau wkSheet.PrintOut(EmptyParam,EmptyParam,1, EmptyParam,EmptyParam,LCID); Benannte Bereiche und Makros komplexer. Ein besserer Ansatz besteht darin, bestimmte Tabellenbereiche zu benennen und sie dann namentlich zu referenzieren. Names ist eine Sammlungsobjekteigenschaft von WorkBook, die über eine Add-Methode verfügt, die diese Aufgabe übernehmen kann. Var Aname : Excel2000.Name; …… Aname := wkBook.Names.Add('Adressbuch','=Sheet1!$A$3:$D$7', EmptyParam, EmptyParam, EmptyParam,EmptyParam,EmptyParam,EmptyParam, EmptyParam, EmptyParam,EmptyParam); Der erste Parameter der Add-Funktion ist der definierte Name und der zweite Parameter ist der durch den Namen dargestellte Zellbereich. Es ist zu beachten, dass der Typ des Bereichsnamens einen Qualifizierer verwenden muss. Wenn eine Typbibliothek (D4) verwendet wird, ist der Qualifizierer Excel_TLB. Darüber hinaus sollte der benannte Bereich eine absolute Referenz verwenden, d. h. das Symbol „$“ hinzufügen. Sobald Sie einen Bereich benennen, können Sie ihn mit diesem Namen referenzieren. Die folgende Codezeile lässt den Inhalt des Adressbuchs fett erscheinen: AName.RefersToRange.Font.Bold:=True. Das Überraschendste ist jedoch, dass Sie dies dynamisch tun können Ändern Sie Excel-Makroprogramme in Delphi! Der folgende Code erstellt ein Makro für unsere Arbeitsmappe, das den letzten Zugriffszeitpunkt beim Schließen der Arbeitsmappe aufzeichnet: var LineNo: integer CM: CodeModule; begin CM := WkBook.VBProject.VBComponents.Item( 'ThisWorkbook'). Codemodule; LineNo := CM.CreateEventProc('BeforeClose', 'Workbook'); SDate:='Last access date:'+DateToStr(Date()); CM.InsertLines(LineNo + 1, ' Range("B2").Value = "'+sDate+''"'); Das Makro fügt dem vorherigen Verwendungsabschnitt eine Einheit hinzu: VBIDE2000. Wenn eine Typbibliothek verwendet wird, ist die entsprechende Einheit VBIDE_TLB. Der Schlüssel zu diesem Code ist das CodeModule-Objekt. Leider gibt es im Excel VBA-Hilfedokument keine Spur von diesem Objekt, daher können wir nur MSDN durchsuchen. Delphi4 und frühere Versionen Delphi4 stellen das TExcelApplication-Objekt nicht bereit und zur Verwendung der OLE-Automatisierungstechnologie muss eine Typbibliothek eingeführt werden. Die Typbibliothek von Excel97 ist Excel8.olb. Der Hauptunterschied zwischen diesen beiden Methoden besteht in der Methode zum Herstellen einer Verbindung mit dem Serverprogramm. Das Folgende ist das Programm-Framework zur Steuerung von Excel über die Typbibliothek: verwendet Windows, ComObj, ActiveX, Excel_TLB; _Application; ; Unknown:IUnknown; Ergebnis: HResult; begin LCID:= LOCALE_USER_DEFAULT:= GetActiveObject(CLASS_Application, nil, Unknown); //Versuchen Sie, die laufende Programminstanz zu erfassen if (Result = MK_E_UNAVAILABLE) then Excel := CoApplication.Create //Eine neue Programminstanz starten else begin {Auf Fehler während des GetActiveObject-Methodenaufrufs prüfen} OleCheck(Result); (Unknown.QueryInterface(_Application, Excel)); end; …… //Datenverarbeitung durchführen Excel.Visible[LCID] := True; // Excel.DisplayAlerts[LCID] := False; //Prompt-Dialogfeld anzeigen Excel.Quit; Die übliche try...exclusive-Struktur wird hier nicht verwendet, da der Ausnahmebehandlungsmechanismus komplexe OLE-Prüfungen erfordert die Kosten Die Ausführungsgeschwindigkeit des Ausnahmeteils. Es ist zu beachten, dass die zugehörige Funktion CoApplication und einige von verschiedenen Delphi-Versionen generierte Konstantennamen unterschiedlich sein können. Überprüfen Sie daher die entsprechende Typbibliothek. Stellen Sie vor dem Aufrufen der Quit-Methode sicher, dass alle im Programm erstellten Arbeitsmappen- und Arbeitsblattvariablen freigegeben werden, da Excel sonst möglicherweise im Speicher verbleibt und ausgeführt wird (zum Anzeigen können Sie Strg+Alt+Entf drücken). Es gibt ein kleines Problem beim Aufruf von GetActiveObject zum Erfassen der Programminstanz. Wenn sich Excel in einem minimierten Ausführungszustand befindet, wird möglicherweise nur der Hauptrahmen des Programms angezeigt und der Benutzerbereich ist nicht sichtbar. Wenn Sie keine Typbibliothek einführen möchten, können Sie außerdem auch eine verzögerte Bindung verwenden, diese ist jedoch viel langsamer. Das folgende Beispiel deklariert eine Variant-Variable zur Darstellung der Excel-Anwendung: var Excel: Variant; ... try Excel := GetActiveOleObject('Excel.Application'); .Visible := True; Wenn eine verzögerte Bindung verwendet wird, überprüft der Compiler nicht die aufgerufene Excel-Objektmethode, sondern überlässt diese Aufgaben dem Serverprogramm, um sie während der Ausführung auszuführen. Auf diese Weise wird eine große Anzahl von Standardparametern festgelegt, die von VBA festgelegt werden (oft mehr als ein Dutzend). werden so verwendet, wie sie sollten. Daher hat diese Methode einen unerwarteten Vorteil: Der Code ist prägnant: var WBk, WS, SheetName: OleVariant; ..... WBk := Excel.WorkBooks.Open('C:/Test. xls') ;WS := WBk.Worksheets.Item['SheetName']; …… WBk.Close(SaveChanges := True); wenn Sie in der Typbibliothek definierte Konstanten verwenden möchten , einfach Sie können es nur selbst tun: const xlWBATWorksheet = -4167 …… XLApp.Workbooks.Add(xlWBatWorkSheet); Vergessen Sie nicht, die Variablen nach dem Schließen von Excel freizugeben: Excel := Unassigned; Das Folgende ist der im Beispiel dieses Artikels verwendete Quellcode, der unter Delphi6+MSOffice2000 übergeben wurde. Unit Unit1; Schnittstelle verwendet Windows, Nachrichten, Grafiken, Steuerelemente, Formulare, OleServer, Excel2000, Grids, StdCtrls; Typ TForm1 = class(TForm) Button1: TStringGrid; procedure FormActivate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure OpenExl; procedure Retrieve; var Form1 ; Implementierung {$R *.dfm} verwendet VBIDE2000; wkSheet:_WorkBook; LCID:Integer; Rows[1].CommaText:='Zhang San, männlich, 25.010-33775566'; Rows[2].CommaText:='Li Si, männlich, 47.012-6574906'; Rows[3].CommaText:='Freitag, weiblich ,18,061-7557381'; Rows[4].CommaText:='Sun Tao, 31,3324559'; end; begin with Excel do begin Connect; , LCID); wkBook.Sheets[1] as _WorkSheet; TForm1.Write2Xls; var Datas:Variant; i,j:Integer; begin ir:=StringGrid1.ColCount; Datas:=varArrayCreate([1,ir,1,ic],varVariant); :=1 zu ir do für j:=1 zu ic do Datas[i,j]:=StringGrid1.Cells[j-1,i-1]; with wkSheet do begin Activate(LCID); .Item[3,1],cells.Item[ir+2,ic]].Value:=Datas; // Excel.Visible[LCID]:=True; Datas:=Unassigned; procedure TForm1.Retrieve; var Datas:Variant; i,j:Integer; begin with wkSheet(xlCellTypeLastCell,EmptyParam).Activate; =Excel.ActiveCell.Column; Datas:=Range[Cells.Item[1,1],Cells.Item[ir,ic]].Value; with StringGrid1 do begin ColCount:=ic; ScrollBars:=ssBoth; to ir-1 do for j:=0 to ic-1 do Cells[j,i]:=Datas[i+1,j+1]; Datas:=UnAssigned; end; procedure TForm1.CloseExl; begin wkBook.Close(True,SaveAsName,LCID); end; NameSheet; beginnen AName:=wkBook.Names.Add('Adressbuch','=Sheet1!$A$3:$D$7',EmptyParam,EmptyParam, EmptyParam,EmptyParam,EmptyParam, EmptyParam,EmptyParam,EmptyParam); Ende; .AddFormula; var AFormula:String; AFormula:='=Rand()'; wkSheet.Range['F3','G6'].Value:=AFormula end; Font do begin Merge(True); //Zellen zusammenführen HorizontalAlignment:= xlCenter; FontStyle:=Bold; end; wkSheet.EntireColumn.AutoFit; with Aname.RefersToRange,Borders do begin Item[xlInsideHorizontal].Weight:=xlThin; end; var LineNo: sDate:String; VBComponents.Item('ThisWorkbook').Codemodule; LineNo := CM.CreateEventProc('BeforeClose', 'Workbook'); SDate:='Last access date:'+DateToStr(Date()); CM.InsertLines(LineNo + 1, ' Range("B2").Value = "'+sDate+'"'); end; procedure TForm1.Printit; begin with wkSheet.PageSetUp do begin PaperSize:=xlPaperA4; //Papiertyp A4 PrintTitleRows := 'A1:D1'; //Diese Zeile/Seite wiederholen LeftMargin:=18; //0.25" Left Margin:=18; //0.25" variiert zwischen Druckern TopMargin:=36; //0.5" BottomMargin:=36; //0.5" CenterHorizontally:=True; Orientierung:=1; //Landschaft=2, Porträt=1 end; wkSheet.PrintOut(EmptyParam,EmptyParam,EmptyParam, EmptyParam,EmptyParam,LCID); end; ; Beginnen Sie mit OpenExl; NameSheet; PrintIt; schließlich CloseExl; 2002/4/14 eine seiner wichtigsten Funktionen, doch die schwierig zu bedienende QuickReport-Steuerung kann den Anforderungen von Datenbankberichten oft nicht gerecht werden. Wenn Ihr Bericht sehr komplex ist oder Flexibilität bei Formatänderungen erfordert, ist die Verwendung von Excel als Berichtsserver eine gute Wahl. Die von Delphi ab Version 5 bereitgestellte Excel-Komponente vereinfacht die Anwendung der OLE-Automatisierungstechnologie erheblich. Allerdings waren die fehlenden Hilfedateien schon immer der am meisten kritisierte Aspekt von Delphi, und diese neuen Komponenten bilden da keine Ausnahme. In diesem Artikel wird versucht, dies detaillierter vorzustellen. Das Objektmodell von Excel ist eine baumartige hierarchische Struktur. Das Arbeitsblatt, das hauptsächlich für den Datenaustausch verwendet wird, ist das Attributobjekt der Arbeitsmappe Weitere Informationen finden Sie in der MSOffice Excel VBA-Hilfedatei. Um Excel in Delphi zu steuern, müssen Sie zunächst eine Verbindung mit dem Serverprogramm herstellen, die Arbeitsmappe öffnen, dann Daten mit dem Zielarbeitsblatt austauschen und schließlich die Verbindung trennen. Öffnen Sie die Excel-Arbeitsmappe. Unser Beispiel beginnt mit einem Hauptformular mit einem TStringGrid (natürlich müssen einige Daten ausgefüllt werden) und zwei Schaltflächen. Ziehen Sie ein TExcelApplication-Steuerelement aus der Registerkarte „Server“ des Bedienfelds und platzieren Sie es auf dem Formular. Setzen Sie ConnectKind zunächst auf ckRunningOrNew. Das heißt, wenn die laufende Excel-Instanz erkannt werden kann, stellen Sie Kontakt mit ihr her, andernfalls starten Sie Excel. Wenn Sie möchten, dass das Programm außerdem sofort nach der Ausführung Kontakt zum Serverprogramm herstellt, können Sie die Eigenschaft AutoConnect auf True setzen. Um den Kontakt zu Excel herzustellen, ist nur eine Anweisung erforderlich: Excel Connect; Excel . ActiveWorkbook); ExcelWorksheet1.ConnectTo(Excel . ActiveSheet as _Worksheet2.ConnectTo(Excel . Worksheets.Item['Sheet2']); _Worksheet); Es ist zu beachten, dass vor der Verwendung der ConnectTo-Methode die entsprechende Arbeitsmappe oder das entsprechende Arbeitsblatt geöffnet werden muss. Darüber hinaus bringen diese Steuerelemente in den meisten Fällen keinen zusätzlichen Komfort, daher ist es am besten, nur eine TExcelApplication zu verwenden. Sobald der Kontakt mit dem Excel-Server hergestellt ist, kann eine neue Arbeitsmappe erstellt werden: var LCID : Integer; ... LCID := GetUserDefaultLCID(); Funktion Der erste Parameter wird verwendet, um die für die neue Arbeitsmappe verwendete Vorlage zu definieren. Sie können xlWBATChart, xlWBATExcel4IntlMacroSheet, verwenden. xlWBATExcel4MacroSheet- oder xlWBATWorksheet-Konstante, oder es kann der Name einer vorhandenen XLS-Datei sein. Das EmptyParam ist hier die Variants-Einheit und die definierte Variable, was bedeutet, dass die standardmäßige universelle Vorlage zum Erstellen einer neuen Arbeitsmappe verwendet wird. Wenn Sie ein vorhandenes XLS-Dokument öffnen, sollten Sie den zu öffnenden Dateinamen als ersten Parameter an die Open-Funktion übergeben: wkBook:=Excel.WorkBooks.Open(edtDesFile.text,EmptyParam,EmptyParam, EmptyParam,EmptyParam,EmptyParam,EmptyParam , EmptyParam,EmptyParam,EmptyParam,EmptyParam, EmptyParam,EmptyParam,LCID); Sie müssen wissen, dass alle Datenoperationen hauptsächlich für das aktive Arbeitsblatt gelten. Die folgende Anweisung verwendet eine _WorkSheet-Variable, um die aktuell aktive Zelle darzustellen. Wenn Sie den Namen des Arbeitsblatts kennen, kann die Indexnummer durch den Arbeitsblattnamen ersetzt werden: wkSheet:=wkBook.Sheets[1] as _WorkSheet; Nach Abschluss des Datenaustauschs müssen Sie die Arbeitsmappe speichern: Excel.ActiveWorkBook.SaveAs ('MyOutput', EmptyParam ,EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, LCID); oder: Excel.ActiveWorkBook.Save(LCID); Schließen Sie schließlich die Arbeitsmappe und trennen Sie die Verbindung zu Excel: wkBook.Close(True, SaveAsName, LCID); //Excel.Quit; ; Die Close-Methode enthält hier die Speicherfunktion. Der erste Parameter gibt an, ob die Änderungen gespeichert werden sollen, bevor die Arbeitsmappe geschlossen wird. Der dritte Parameter wird für die Verarbeitung des Dokuments verwendet. Die zweite Zeile fordert zum Beenden von Excel auf. Datenaustausch mit dem Arbeitsblatt Die Eingabedaten werden für eine bestimmte Zelle oder einen bestimmten Bereich des aktiven Arbeitsblatts ausgeführt. Bereich und Zellen sind beide Objekteigenschaften des Arbeitsblatts. „Cells“ ist eine Sammlung von Zellen. Wenn kein bestimmter Speicherort angegeben ist, kann sie alle Zellen im gesamten Arbeitsblatt darstellen. Im Allgemeinen wird sie jedoch verwendet, um auf eine bestimmte Zelle zu verweisen. stellt die aktuellste Zelle in der oberen linken Ecke dar. Beachten Sie, dass „Item“ die Standardeigenschaft von „Cells“ in VBA ist und weggelassen werden kann, in Delphi gibt es diese Funktion jedoch nicht. Um einer Zelle einen Wert zuzuweisen, müssen Sie auf deren Value-Eigenschaft verweisen. Es versteht sich von selbst, dass diese Eigenschaft eine Variant-Variable ist, zum Beispiel: wkSheet.Cells.Item[1, 1].Value := 'Address Book'; Natürlich können Sie einer Zelle auch einen Wert zuweisen: var AFormula:String …… AFormula:='=Rand()'; wkSheet.Range['F3','G6'].Value:=AFormula; Die obige Methode ist sehr direkt und einfach, aber sie ist sehr langsam und nicht für große Berichte geeignet. Können also alle Daten der Reihe nach nach Excel übertragen werden? Wir können Range verwenden. Wenn wir es mit der Maus herausziehen, ist es normalerweise ein rechteckiger Bereich. Geben Sie einfach die Positionen seiner oberen linken Ecke und seiner unteren rechten Ecke an, z. B. Range[ 'C3 ','J42']. Hier gibt es ein kleines Problem, denn wenn die Daten 26 Spalten überschreiten (z. B. 100 Spalten) oder der Zielbereich im laufenden Betrieb bestimmt werden muss, ist es schwieriger, Zeichennamen zum Markieren von Zellen zu verwenden. Denken Sie daran, dass wir natürlich auch Zellen verwenden können, da „C3“ die Bezeichnung der Zelle ist, z. B. Range[Cells.Item[1,1], Cells.Item[100,100]]. Es ist denkbar, dass der Wert von Range ein Array sein sollte, aber Sie dürfen Array in Delphi nicht verwenden, um ihm einen Wert zuzuweisen! Denken Sie daran, dass in Delphi der Wert eines Excel-Objekts immer vom Typ Variant ist. var Datas: Variant; Ir, ic: Integer; …… Datas:= varArrayCreate([1,ir,1,ic],varVariant); //Hier ein 100*100 dynamisches Array erstellen… //Werte zuweisen Array-Elemente hier mit wkSheet do Range[cells.Item[3,1],cells.Item[ir+2,ic]].Value:=Datas; Es ist zu beachten, dass sowohl das Arbeitsblatt als auch der Bereich über die Cells-Eigenschaft verfügen. Aus Gründen der Übersichtlichkeit wird hier die with-Anweisung verwendet. Darüber hinaus ist Range gerichtet. Ein mit VarArrayCreate erstelltes eindimensionales Array kann nur einem einzeiligen Range zugewiesen werden. Wenn Sie einen Wert für einen einspaltigen Range definieren möchten, müssen Sie z. B. ein zweidimensionales Array verwenden Beispiel: Datas:=VarArrayCreate([1,100,1 ,1], varVariant); //Erstelle ein 100*1 dynamisches Array. Übrigens gibt Cells.Item[] tatsächlich ein Range-Objekt zurück. Das Abrufen von Daten aus dem Arbeitsblatt ist im Grunde der umgekehrte Vorgang zum Schreiben von Daten. Es muss darauf geachtet werden, wie der Datenbereich des Arbeitsblatts bestimmt wird: var ir, ic : Integer; …… wkSheet.Cells.SpecialCells(xlCellTypeLastCell,EmptyParam ).Activate ; ir := Excel.ActiveCell.Row; ic := Excel.ActiveCell.Column; Die spezielle Zellfunktion SpecialCells wird hier geschickt eingesetzt, um die letzte Zelle mit Daten zu erhalten. Datenbearbeitung Nachfolgend finden Sie zwei Beispiele für die Datenbearbeitung. var DestRange: OleVariant; begin DestRange := Excel.Range['C1', 'D4']; Copy(DestRange); Wenn Sie der Copy-Funktion einen leeren Parameter übergeben, werden die Daten in diesem Bereich in die Zwischenablage kopiert und können später mit der Paste-Methode an anderen Stellen eingefügt werden. var WS: _Worksheet; …… Excel.Range['A1', 'B4'].Copy(EmptyParam); //Daten in ein Arbeitsblatt in die Zwischenablage kopieren WS := Excel.Activesheet as _Worksheet WS; .Range['C1', 'D4'].Select; WS.Paste(EmptyParam, EmptyParam, lcid); //Fügen Sie den Inhalt der Zwischenablage in ein neues Arbeitsblatt ein. Formateinstellungen Wählen Sie Excel als Berichtsserver, hauptsächlich wegen seiner leistungsstarken Formatierungsfunktionen. Wir führen zunächst die Zellen mit dem Titel „Adressbuch“ zusammen und zeigen ihn in der Mitte an. Anschließend ändern wir die Schriftart in „offizielle Schrift“ mit 18 Punkt Fettschrift: mit wkSheet.Range['A1','D1'],Font do begin Merge(True); //Zellen zusammenführen HorizontalAlignment:= xlCenter; Name:='official script'; Wenn der Zelleninhalt lang ist, wird ein Teil des Inhalts nicht angezeigt. Die übliche Vorgehensweise besteht darin, auf den rechten Rand des ausgewählten Bereichs zu doppelklicken, damit sich die Breite jeder Spalte automatisch an die Länge des Inhalts anpasst. In Delphi können adaptive Spaltenbreite und Zeilenhöhe auch über die AutoFit-Methode erreicht werden. Es ist zu beachten, dass diese Methode nur für die gesamte Zeile und gesamte Spalte verwendet werden kann, andernfalls wird ein Fehler angezeigt, dass die Ausführung der OLE-Methode verweigert wird: wkSheet.Columns.EntireColumn.AutoFit; Berichte im chinesischen Stil erfordern normalerweise obere und untere begrenzte Tabellenzeilen, und Sie können die Borders-Sammlungseigenschaft verwenden. Es ist zu beachten, dass Sammlungsobjekte in VBA normalerweise über eine Standard-Item-Eigenschaft verfügen, die in Delphi nicht weggelassen werden kann. Die Weight-Eigenschaft wird verwendet, um die Dicke von Tabellenlinien zu definieren: mit Aname.RefersToRange,Borders do begin HorizontalAlignment:= xlRight Item[xlEdgeTop].Weight:=xlMedium; .Gewicht: =xlThin; item[xlInsideVertical].Weight:=xlThin; Seiteneinrichtung und Druckseiteneinrichtung werden über die Objekteigenschaft PageSetUp des Arbeitsblatts festgelegt. In Excel VBA sind mehr als 40 Papierkonstanten voreingestellt. Es ist zu beachten, dass einige Drucker nur einige der Papiertypen unterstützen. Das Attribut „Ausrichtung“ dient zur Steuerung der Druckrichtung und die Konstante „Landschaft = 2“ gibt horizontales Drucken an. Die booleschen Eigenschaften CenterHorizontally und CenterVertically werden verwendet, um zu bestimmen, ob der gedruckte Inhalt horizontal und vertikal zentriert ist. with wkSheet.PageSetUp do begin PaperSize:=xlPaperA4; //Papiertyp A4 PrintTitleRows := 'A1:D1'; //Repeat this row/page LeftMargin:=18; //0.25" Left Margin RightMargin:=18; // 0,25" variiert zwischen den Druckern. TopMargin:=36; //0,5" BottomMargin:=36; //0,5" CenterHorizontally:=True; Orientation:=1; //Horizontaler Druck (Querformat)=2, Hochformat=1 end; Sie können die PrintOut-Methode des Arbeitsblatts aufrufen optionale Parameter, die ersten beiden werden verwendet, um die Anfangs- und Endseiten sowie die Anzahl der gedruckten Kopien im dritten Format anzugeben. In Delphi wird jedoch am Ende ein LCID-Parameter hinzugefügt, und EmptyParam kann für diesen Parameter nicht verwendet werden. Ebenso verfügt die Druckvorschau-Methode PrintPreview in VBA über keine Parameter, erfordert jedoch beim Aufruf in Delphi zwei Parameter. // WKBook.printPreview (True, LCID); Komplexer, ein besserer Ansatz besteht darin, bestimmte Tabellenbereiche zu benennen und sie dann mit Namen zu verweisen. NAME ist eine Sammelobjekteigenschaft des Arbeitsmappens, die eine Methode hinzufügen, die diesen Job erledigen kann. Var Aname: Excel2000.Name; Leerparam, leerparam); Der erste Parameter der Add -Funktion ist der definierte Name, und der zweite Parameter ist der vom Namen dargestellte Zellbereich. Es ist zu beachten, dass der Typ des Reichweite einen Qualifikationsspiel verwenden muss. Darüber hinaus sollte der benannte Bereich absolute Referenz verwenden, dh das Symbol "$" hinzuzufügen. Sobald Sie einen Bereich nennen, können Sie ihn mit diesem Namen verweisen. Ändern Sie Excel -Makroprogramme in Delphi! Der folgende Code erstellt ein Makro für unsere Arbeitsmappe, die die letzte Zugriffszeit beim Schließen der Arbeitsmappe aufzeichnet: VAR LINENO: Integer; Codemodule; SDATE: = 'Letzter Zugriff:'+DateToStr (Date ()); Das Makro fügen Sie dem vorherigen Verwendungsabschnitt ein Gerät hinzu: VBIDE2000. Der Schlüssel zu diesem Code ist das Codemodul -Objekt. Delphi4 und frühere Versionen Delphi4 liefert nicht das TexCelApplication -Objekt, und eine Typbibliothek muss eingeführt werden, um die OLE -Automatisierungstechnologie zu verwenden. Der Hauptunterschied zwischen diesen beiden Methoden ist die Methode zur Erstellung einer Verbindung mit dem Serverprogramm ; Unbekannt); (Unbekannte.QueryInterface (_Application, Excel)); Richtig; die kostete die Ausführungsgeschwindigkeit des außer einem Teil. Es ist zu beachten, dass die mit verschiedenen Delphi -Versionen generierte begleitende Funktionskopplikation und einige konstante Namen unterschiedlich sein können. Sie sollten daher die entsprechende Typbibliothek überprüfen. Bevor Sie die Quit -Methode aufrufen, veröffentlichen Sie alle im Programm erstellten Arbeitsmappen- und Arbeitsblattvariablen, da sich Excel im Speicher befindet und ausgeführt wird (Sie können Strg+Alt+del drücken, um sie anzeigen). Es gibt ein kleines Problem beim Aufrufen von GetActiveObject, um die Programminstanz zu erfassen. Wenn Sie keine Bibliothek einführen möchten, können Sie außerdem eine Verzögerungspflicht verwenden, aber sie ist viel langsamer. Das folgende Beispiel deklariert eine Variante, um die Excel -Anwendung darzustellen: Var Excel: Variante; .Vissible: = wahr; Wenn die Verzögerungsbindung verwendet wird, überprüft der Compiler die aufgerufene Excel -Objektmethode nicht, lässt diese Aufgaben auf diese Weise im Serverprogramm abgeschlossen. werden so verwendet. XLS '); WS : = WBK.Worksheets.Item ['SheetName']; Sie können es nur selbst tun: const xlwbatworksheet = -4167; Vergessen Sie nicht, die Variablen nach dem Schließen von Excel: Excel: = nicht zugewiesen; Einheit1; Prozedur formActivate (Absender: Tobject); Button1Click (Absender) ; WKSheet: _Worksheet; Zeilen [1] 18.061-7557381 '; Zeilen [4] , Lcid); Tform1.Write2XLS; : = 1 zu ir tun für j: = 1 zu ic do do Datas [i, j]: = stringgrid1.cells [J-1, I-1]; .Item [3,1], Cells.Item [Ir+2, IC]]. Wert: = datas; DataS: = nicht zugewiesen; = Excel.activecell.column; Datas: = Bereich [Cells.Item [1,1], Zellen [ir, IC] zu ir-1 für j: = 0 bis IC-1-do-Zellen [j, i]: = datas [i+1, j+1]; DataS: = enden; Namshose; Aname: = wkbook.names.Add ('Adressbuch', '= Sheet1! .Addformula; Aformula: = '= Rand ()'; Schriftart beginnen (true); FontStyle: = Ende; Item [xlinsideHorizontal] .gewicht: = xlthin; VbComponents.Item ('Thisworkbook'). Codemodule; : = Cm.createEventProc ('Beforeclose', 'Workbook'); "'+sdate+'"); Papiere: = xlpapera4; TopMargin: = 36; Orientierung: = 1; ; Namesheet;