Excel mit OLE-Automation steuern |
|
| Autor | Deborah Pate |
|---|---|
| System | Win9x, WinNT, Win2000, WinXP, Vista, Win7 |
| Ab Delphi-Version | Delphi 5 |
| Letzte Änderung | 20.02.2012 |
Wie kann ich Excel starten?
Die Komponenten (seit Delphi 5) machen das Starten von Excel sehr einfach. Setzen Sie eine ExcelApplication-Komponente auf Ihr Formular. Falls sie in der Toolpalette nicht zu finden ist, muss im Menü Komponente / Packages installieren ein Haken gesetzt werden vor "Microsoft Office XP Beispiele für gekapselte Komponenten für Automation Server".
Wenn die AutoConnect-Eigenschaft true ist, wird Excel automatisch gestartet, wenn Ihr Programm startet; wenn die Eigenschaft false ist, rufen Sie einfach
auf, wenn Sie Excel starten wollen. Um eine laufende Instanz von Excel zu verwenden, sofern es eine gibt, setzen Sie die ConnectKind-Eigenschaft von TExcelApplication auf ckRunningOrNew oder auf ckRunningInstance, wenn Sie keine neue Instanz starten wollen, wenn Excel nicht läuft.
Ist Excel einmal gestartet, können Sie andere Komponenten wie TExcelWorkbook, verbinden, indem Sie deren ConnectTo-Methode verwenden:
ExcelWorksheet1.ConnectTo(ExcelApplication1.ActiveSheet as _Worksheet);
ExcelWorksheet2.ConnectTo(ExcelApplication1.Worksheets.Item['Sheet2'] as _Worksheet);
Beachten Sie, dass ein Workbook oder ein Worksheet geöffnet werden muss, bevor Sie es verbinden können! Mehr dazu weiter unten.
Ich empfehle Ihnen jedoch, Excel nicht auf eine andere Art zu starten, als durch die Verwendung der Application-Komponente. Zumindest auf einigen Installationen verursacht der Aufruf der Connect-Methode (nicht der ConnectTo-Methode!) einer Workbook- oder einer Worksheet-Komponente eine Exception.
Excel öffnen (frühe Bindung)
Bevor Sie diese Methode nutzen können, müssen Sie die Typbibliothek (Excel8.olb für Excel 97) importieren.
Eine Art, Excel zu starten, ist der Versuch (try), GetActiveObject aufzurufen, um eine laufende Instanz von Excel zu erhalten, setzen Sie jedoch einen Aufruf von CoApplication.Create in den except-Abschnitt. Aber except-Klauseln sind langsam und können bei Leuten, die gerne "Bei Exceptions anhalten" aktiviert haben, Probleme innerhalb der IDE auslösen. Der folgende Code benötigt keine try-except-Konstruktion, weil die Verwendung von OleCheck bei GetActiveObject im Fall, dass Excel nicht läuft, vermieden wird.
var
Excel: _Application;
AppWasRunning: boolean; // tells you if you can close Excel when you've finished
lcid: integer;
Unknown: IUnknown;
Result: HResult;
begin
lcid := LOCALE_USER_DEFAULT;
AppWasRunning := False;
{$IFDEF VER120} // Delphi 4
Result := GetActiveObject(CLASS_Application_, nil, Unknown);
if (Result = MK_E_UNAVAILABLE) then
Excel := CoApplication_.Create
{$ELSE} // Delphi 5
Result := GetActiveObject(CLASS_ExcelApplication, nil, Unknown);
if (Result = MK_E_UNAVAILABLE) then
Excel := CoExcelApplication.Create
{$ENDIF}
else begin
{ make sure no other error occurred during GetActiveObject }
OleCheck(Result);
OleCheck(Unknown.QueryInterface(_Application, Excel));
AppWasRunning := True;
end;
Excel.Visible[lcid] := True;
...
Es gibt jedoch ein Problem, vor dem Sie sich hüten sollten: Excel mit GetActiveObject zu starten, kann dazu führen, dass Excels Hauptfenster angezeigt wird, sein Client-Gebiet jedoch verborgen bleibt. Obwohl Sie das Client-Gebiet dadurch wiederherstellen können, indem Sie Excel auf Vollbild und wieder zurück setzen, ist das ein offensichtlich unattraktives Verhalten. Es scheint nur aufzutreten, wenn Excel zum Zeitpunkt des GetActiveObject-Aufrufs unsichtbar läuft.
Excel mag unsichtbar laufen, auch wenn Sie denken, Sie hätten es freigegeben, wenn eine Ihrer Workbook- oder Worksheet-Variablen noch "leben". (Prüfen Sie dies, indem Sie Strg+Alt+Entf drücken und die Liste der laufenden Tasks durchsehen.) Wenn Sie sicher sind, alle Excel-Variablen freigegeben zu haben, wenn Sie die Anwendung beenden, wird Excel sauber beendet werden. Der folgende Start der Anwendung verursacht normalerweise keine Probleme, vor allem wenn die Anwender Ihrer Software Excel nicht durch eine andere Methode unsichtbar laufen haben.
Wenn Ihre Anwender jedoch evtl. andere Software verwenden, die Excel unsichtbar laufen lässt, sollten Sie es vorziehen, alle Aufrufe von GetActiveObject (oder GetActiveOleObject) zu vermeiden und einfach CoApplication.Create zu verwenden.
Ohne Verwendung der Typbibliothek
Automation ist sehr viel schneller und einfacher, wenn Typbibliotheken (frühe Bindung) verwendet werden, deshalb sollten Sie es, wenn immer möglich, vermeiden, ohne sie zu arbeiten. Aber wenn es wirklich nicht anders geht, hier, wie vorzugehen ist:
Excel: Variant;
begin
try
Excel := GetActiveOleObject('Excel.Application');
except
Excel := CreateOleObject('Excel.Application');
end;
Excel.Visible := True;
Wie kann ich Excel schließen?
Eine Application-Variable Excel und eine Integer-Variable LCID, der Sie den Wert GetUserDefaultLCID zugewiesen haben, vorausgesetzt:
Frühe Bindung:
whether to save the worksheet }
// Excel.DisplayAlerts[LCID] := False;
Excel.Quit;
Wenn Sie die D5-Server-Komponenten verwenden, sollten Sie die Verbindung lösen:
Wenn Sie eine _Application-Interface-Variable verwenden, sollten Sie diese stattdessen auf nil setzen:
Späte Bindung:
whether to save the worksheet }
// Excel.DisplayAlerts := False;
Excel.Quit;
Excel := Unassigned;
Beachten Sie jedoch, dass Excel unsichtbar laufend im Hauptspeicher verbleibt, wenn Sie nicht alle Ihre Workbook- und Worksheet-Variablen freigegeben haben. Trennen Sie die Verbindung aller Komponenten (disconnect), setzen Sie alle Interface-Variablen auf nil und setzen Sie Variant-Variablen auf unassigned, um dies zu verhindern. Wie kann ich ein Workbook erzeugen?
Eine Application-Variable Excel und eine Integer-Variable LCID, der Sie den Wert GetUserDefaultLCID zugewiesen haben, vorausgesetzt:
Frühe Bindung:
WBk: _Workbook;
...
WBk := Excel.Workbooks.Add(EmptyParam, LCID);
EmptyParam als ersten Parameter zu verwenden, bedeutet, dass ein neues Workbook mit einer Zahl leerer Sheets erzeugt wird. Wenn Sie als ersten Parameter einen Dateinamen übergeben, wird diese Datei als Vorlage für das neue Workbook verwendet. Alternativ können Sie eine der folgenden Konstanten verwenden: xlWBATChart, xlWBATExcel4IntlMacroSheet, xlWBATExcel4MacroSheet oder xlWBATWorksheet. Das erzeugt ein neues Workbook mit einem einzigen Sheet des angegebenen Typs.
Späte Bindung:
Bei später Bindung müssen Sie keine optionalen Parameter oder LCIDs angeben, weshalb Sie einfach das verwenden können:
Wenn Sie nicht die Typbibilothek verwenden, aber eine der oben erwähnten Konstanten verwenden wollen, können Sie diese in Ihrem Code etwa so definieren:
xlWBATChart = $FFFFEFF3;
xlWBATExcel4IntlMacroSheet = $00000004;
xlWBATExcel4MacroSheet = $00000003;
xlWBATWorksheet = $FFFFEFB9;
Wie kann ich ein Workbook öffnen?
Eine Application-Variable Excel und eine Integer-Variable LCID, der Sie den Wert GetUserDefaultLCID zugewiesen haben, vorausgesetzt:
Frühe Bindung:
WBk: _Workbook;
WS: _WorkSheet;
Filename: OleVariant;
...
Filename := 'C:\Test.xls';
WBk := Excel.Workbooks.Open(Filename, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, LCID);
WS := WBk.Worksheets.Item['Sheet1'] as _Worksheet;
WS.Activate(LCID);
Späte Bindung:
Bei später Bindung müssen Sie keine optionalen Parameter angeben, deshalb können Sie es so machen:
WBk, WS, SheetName: OleVariant;
...
WBk := Excel.WorkBooks.Open('C:\Test.xls');
WS := WBk.Worksheets.Item['SheetName'];
WS.Activate;
Wie kann ich ein Workbook schließen?
Eine _Workbook-Variable WBk und eine Integer-Variable LCID, der Sie den Wert GetUserDefaultLCID zugewiesen haben, vorausgesetzt:
Frühe Bindung:
SaveChanges: OleVariant;
...
SaveChanges := True;
WBk.Close(SaveChanges, EmptyParam, EmptyParam. LCID);
Wenn Sie EmptyParam als SaveChanges-Parameter verwenden, wir der Anwender gefragt werden, ob das Workbook gespeichert werden soll. Der zweite Parameter erlaubt es Ihnen einen Dateinamen anzugeben, und der dritte gibt an, ob das Workbook an den nächsten Empfänger weitergeleitet werden soll.
Späte Bindung:
Bei später Bindung ist es nicht notwendig, optionale Parameter oder die LCID anzugeben, weshalb Sie es so machen können:
oder so:
Wie kann ich Daten eingeben?
Eine _Worksheet-Variable WS vorausgesetzt:
WS.Range['A1', 'A1'].Value := 'The meaning of life, the universe, and everything, is';
WS.Range['B1', 'B1'].Value := 42;
Sie können Daten in viele Zellen auf einmal eingeben:
Sie können auf Zellen über die Zeilen- und Spaltennummer oder über Variablen zugreifen:
Row, Col: integer;
...
WS.Cells.Item[1, 1].Value := 'The very first cell';
WS.Cells.Item[Row, Col].Value := 'Some other cell';
Wie kann ich Daten kopieren?
Von einem Bereich zu einem anderen:
DestRange: OleVariant;
begin
DestRange := Excel.Range['C1', 'D4'];
Excel.Range['A1', 'B4'].Copy(DestRange);
Stellen Sie sicher, dass Sie nicht gerade eine Zelle bearbeiten, wenn Sie den Bereich kopieren wollen, oder Sie bekommen einen 'Call was rejected by callee'-Fehler.
Von einem Sheet in ein anderes:
Dieses Beispiel kopiert die erste Spalte eines Sheets in die zweite Spalte eines anderen:
DestSheet: _Worksheet;
DestRange: OleVariant;
begin
DestSheet := Excel.WorkBooks['Test.xls'].Worksheets['Sheet1'] as _Worksheet;
DestRange := Destsheet.Range['B1', 'B1'].EntireColumn;
Excel.Range['A1', 'A1'].EntireColumn.Copy(DestRange);
Über die Zwischenablage:
Das Verwenden von Copy ohne Ziel-Parameter kopiert die Zellen in die Windows-Zwischenablage:
Sie können diese Zellen dann in einen anderen Bereich einfügen:
WS: _Worksheet;
begin
WS := Excel.Activesheet as _Worksheet;
WS.Range['C1', 'D4'].Select;
WS.Paste(EmptyParam, EmptyParam, lcid);
Wie kann ich einen Bereich formatieren?
Eine _Worksheet-Variable WS vorausgesetzt:
Format: OleVariant;
...
WS := Excel.ActiveSheet as _Worksheet;
Um eine Zelle im generellen Zahlenformat zu formatieren:
WS.Range['A1', 'A1'].NumberFormat := Format;
Um einen Bereich als "Text" rechtsbündig zu formatieren: Sehr sonderbar: Um einem Bereich einen "Text"-Stil zuzuweisen, muss sein NumberFormat auf '@' gesetzt werden.
begin
NumberFormat := '@';
HorizontalAlignment := xlHAlignRight;
end;
Um einen Zellenbereich mit dem Datumsformat "March 4, 1999" zu formatieren:
WS.Range['B1', 'C10'].NumberFormat := Format;
Um eine komplette Spalte in einem benutzerdefinierten Währungsstil zu formatieren:
WkSheet.Range['C1', 'C1'].EntireColumn.NumberFormat := Format;
Um den Text in einer Zelle auf 20 pt Arial, fett und rosa (fuchsia) zu setzen:
begin
Size := 20;
FontStyle := 'Bold';
Color := clFuchsia;
Name := 'Arial';
end;
Um die Farbe der Zelle zu verändern:
oder
Um die ersten drei Zeichen einer Zelle fett zu machen:
Start, Length: OleVariant;
...
Start := 1;
Length := 3;
Excel.ActiveCell.Characters[Start, Length].Font.FontStyle := 'Bold';
Start := 4;
Length := 16;
Excel.ActiveCell.Characters[Start, Length].Font.FontStyle := 'Regular';
Wie kann ich einem Workbook einen Namen zuweisen?
WB: _Workbook;
N: Excel_TLB.Name; // or N := Excel97.Name; if you're using D5
begin
WB := Excel.ActiveWorkbook;
N := WB.Names.Add('AddedName', '=Sheet1!$A$1:$D$3', EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam);
Der erste Parameter ist der neue Name, der zweite, worauf sich der Name bezieht. Wenn der dritte Parameter auf false gesetzt wird, wird der Name versteckt und erscheint nicht in den Define Name- oder Goto-Dialogen.
Zwei mögliche Probleme sind hier anzumerken. Erstens: Um eine Variable des Typs "Name" zu deklarieren, müssen Sie es wahrscheinlich ausdrücklich so machen:
Zweitens: Beachten Sie, dass das $-Zeichen im RefersTo-Parameter wichtig ist. Es wegzulassen, verursacht eine unterschiedliche Zahl unerwarteter Ergebnisse.
Wie kann ich einem Workbook ein Makro hinzufügen?
Sie können Excel-VBA-Code zur Laufzeit verändern, indem Sie ihn direkt in das Code-Modul des Excel-VBA-Editors schreiben, Zeilen oder Ereignisse hinzufügen oder entfernen. Das wichtige Objekt hierbei ist das CodeModule-Objekt (geschickterweise sehr schwer in der Excel-VBA-Hilfe zu finden). Es ist in der VBIDE97.pas-Datei deklariert. Hier ein Beispiel, wie es genutzen werden kann:
VBIDE97; // or VBIDE_TLB for Delphi 4
var
LineNo: integer;
CM: CodeModule;
begin
CM := WBk.VBProject.VBComponents.Item('ThisWorkbook').Codemodule;
LineNo := CM.CreateEventProc('Activate', 'Workbook');
CM.InsertLines(LineNo + 1, ' Range("A1").Value = "Workbook activated!"');