![]() |
Problem mit Excelexport
Hallo,
ich habe ein Problem mit dem Exportieren einer Datenmenge nach Excel, also meine procedure läuft wunderbar auf Rechnern auf denen Excel installiert ist, aber wen Excel nicht installiert ist kommt eine Fehlermeldung das die classID (oder so ähnlich) nicht registriert ist. Also meine Frage jetzt: Wie kann ich meine procedure möglichst einfach verändern das sie auch auf Rechnern angewandt werden kann auf denen kein Excel installiert ist :?: Hier mal mein derzeitiger Code:
Delphi-Quellcode:
Ich weiß, die Sache mit der Stringlist und dem hinzufügen der Felder ist nicht gerade die eleganteste Methode aber es musste einfach schnell gehn und mit ist nichts besseres eingefallen, falls hier jemand etwas besseres kennt würde ich mich über Tipps freun. :)
procedure ExcelExport(SaveDialog : TSaveDialog; ExcelAppli : TExcelApplication;
ExcelWb : TExcelWorkbook; ExcelWsht : TExcelWorksheet; Query : TVddQuery); var Filename, CoordCounter: String; oleArray1, oleArray2:OleVariant; i, z, flcid : Integer; sl, sl2 : TStringlist; begin Screen.Cursor := crHourglass; SaveDialog.Execute; case SaveDialog.FilterIndex of 1: Filename := ChangeFileExt(SaveDialog.FileName,'.xls'); 2: Filename := ChangeFileExt(SaveDialog.FileName,'.xls'); end; if Filename <> '' then begin flcid:=GetUserDefaultLCID; ExcelAppli.Connect; ExcelAppli.Visible[flcid]:=true; ExcelAppli.UserControl:=true; CreateFile(@Filename[1], 0, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); ExcelWb.ConnectTo(ExcelAppli.Workbooks.Open(filename, False, False, EmptyParam, '', False, False, EmptyParam, EmptyParam, false, false, EmptyParam, EmptyParam, EmptyParam, false, 0)); ExcelWsht.ConnectTo(ExcelWb.Sheets.Item[1] as ExcelWorkSheet); sl := TStringList.Create; sl2 := TStringList.Create; Query.GetFieldNames(sl); OleArray1 := VarArrayCreate([0, Query.RecordCount], varVariant); OleArray2 := VarArrayCreate([0, sl.Count], varVariant); for z := 0 to sl.Count - 1 do begin OleArray2[z] := sl.Strings[z]; end; sl2.Add('A'); sl2.Add('B'); sl2.Add('C'); sl2.Add('D'); sl2.Add('E'); sl2.Add('F'); sl2.Add('G'); sl2.Add('H'); sl2.Add('I'); sl2.Add('J'); sl2.Add('K'); sl2.Add('L'); sl2.Add('M'); sl2.Add('N'); sl2.Add('O'); sl2.Add('P'); sl2.Add('Q'); sl2.Add('R'); sl2.Add('S'); sl2.Add('T'); sl2.Add('U'); sl2.Add('V'); sl2.Add('W'); sl2.Add('X'); sl2.Add('Y'); sl2.Add('Z'); sl2.Add('AA'); sl2.Add('AB'); sl2.Add('AC'); sl2.Add('AD'); sl2.Add('AE'); sl2.Add('AF'); sl2.Add('AG'); sl2.Add('AH'); sl2.Add('AI'); sl2.Add('AJ'); sl2.Add('AK'); sl2.Add('AL'); sl2.Add('AM'); sl2.Add('AN'); sl2.Add('AO'); sl2.Add('AP'); sl2.Add('AQ'); sl2.Add('AR'); sl2.Add('AS'); sl2.Add('AT'); sl2.Add('AU'); sl2.Add('AV'); sl2.Add('AW'); sl2.Add('AX'); sl2.Add('AY'); sl2.Add('AZ'); ExcelWsht.Range[sl2[0]+'1', sl2[sl.Count-1]+'1'].Value[EmptyParam] := OleArray2; if sl.count > sl2.Count then begin ExcelWsht.Range[sl2[0]+'1', sl2[sl.Count-1]+'1'].Value[EmptyParam] := OleArray2; end; Query.First; for i := 0 to Query.RecordCount - 1 do begin for z := 0 to sl.Count - 1 do begin OleArray1[z] := Query.FieldByName(sl[z]).AsString; end; CoordCounter := IntToStr(i+2); ExcelWsht.Range[sl2[0]+CoordCounter, sl2[sl.Count-1]+CoordCounter].Value[EmptyParam]:=OleArray1; Query.Next; end; ExcelWsht.Cells.EntireRow.AutoFit; ExcelWsht.Cells.EntireColumn.AutoFit; end; Screen.Cursor := crDefault; sl.Free; sl2.Free; end; Also dann ich hoffe ihr könnt mir weiterhelfen. mfg Alex |
Re: Problem mit Excelexport
Hi,
wenn's hilft: Jet kann von naturaus EXCEL Dateien schreiben:
Delphi-Quellcode:
adoconn := TADOConnection.Create(Application);
try adoconn.ConnectionString := ('Provider=Microsoft.Jet.OLEDB.4.0;Data Source=' + temp); adoconn.CursorLocation := clUseClient; adoconn.LoginPrompt := false; adoconn.Connected := true; adoconn.Execute('SELECT * INTO TestTabelle IN "' + FileName + '" "Excel 8.0; HDR=Yes;" FROM ' + TableName, 1); adoconn.Connected := false; finally adoconn.Free; end; |
Re: Problem mit Excelexport
Hmm eher weniger :( habe gehofft man könnte vielleicht was bei den Parametern für FileCreate ändern.
Aber komplett neue Komponenten zu benutzen wäre der allerletzte Ausweg. |
Re: Problem mit Excelexport
Zum Verständnis: Mit Deinem Beispielcode aus dem Originalposting machst Du nichts anderes, als Excel "fernzusteuern". Deshalb muß Excel auf dem jeweiligen PC logischerweise installiert sein.
|
Re: Problem mit Excelexport
|
Re: Problem mit Excelexport
Nebenbei bemerkt: CreateFile gibt ein Handle zurück, das man schließen sollte.
|
Re: Problem mit Excelexport
Schonmal danke für die hilfreichen Antworten.
Ich habe mal nach TXLsExport gesucht, wie Roga gesagt hatte, nun bin ich da auf einen recht interessanten ![]() Hier habe ich mir diese Unit kopiert:
Delphi-Quellcode:
Also ich habe mir den Aufruf den Marabu gepostet hat schon so umgebaut das ich meine Query benutzen kann. Ein kleines Problem bleibt allerdings noch, und zwar das der linken Seite nichts zugwiesen werden kann. Die betroffenen Stellen habe ich kommentiert.
unit u_ExportEXCEL;
interface uses classes; type TXLSExport = class(TObject) private fs : TFilestream; public constructor Create(filename : string); destructor Destroy; override; procedure Write(const Col, Row: Word; const Value: Integer); overload; procedure Write(const Col, Row: Word; const Value: Double); overload; procedure Write(const Col, Row: Word; const Value: string); overload; end; implementation const CXlsBof : array[0..5] of Word = ($809, 8, 00, $10, 1, 0); CXlsEof : array[0..1] of Word = ($0A, 00); CXlsLabel : array[0..5] of Word = ($204, 0, 0, 0, 0, 0); CXlsNumber : array[0..4] of Word = ($203, 14, 0, 0, 0); CXlsRk : array[0..4] of Word = ($27E, 10, 0, 0, 0); constructor TXLSExport.Create(filename : string); begin inherited Create; fs := TFileStream.Create(filename,fmCreate); fs.WriteBuffer(CXlsBof, SizeOf(CXlsBof)); end; destructor TXLSExport.Destroy; begin fs.WriteBuffer(CXlsEof, SizeOf(CXlsEof)); inherited Destroy; end; procedure TXLSExport.Write(const Col, Row: Word; const Value: Integer); var V: Integer; begin CXlsRk[2] := Row; // CXlsRk[3] := Col; // fs.WriteBuffer(CXlsRk, SizeOf(CXlsRk)); V := (Value shl 2) or 2; fs.WriteBuffer(V, 4); end; procedure TXLSExport.Write(const Col, Row: Word; const Value: Double); begin CXlsNumber[2] := Row; // CXlsNumber[3] := Col; // fs.WriteBuffer(CXlsNumber, SizeOf(CXlsNumber)); fs.WriteBuffer(Value, 8); end; procedure TXLSExport.Write(const Col, Row: Word; const Value: string); var L: Word; begin L := Length(Value); CXlsLabel[1] := 8 + L; //Der linken Seite kann nichts zugewiesen werden. CXlsLabel[2] := Row; //" CXlsLabel[3] := Col; //" CXlsLabel[5] := L; //" fs.WriteBuffer(CXlsLabel, SizeOf(CXlsLabel)); fs.WriteBuffer(Pointer(Value)^, L); end; end. Ich denke es liegt an der Konstantendeklaration, wie kann ich das ändern damit die Unit auch das weiterhin tut wofür sie geschrieben worden ist? Ich hoffe das war halbwegs verständlich. mfg Alex |
Re: Problem mit Excelexport
Hallo Borschti,
also bei mir läufts mit der Unit "u_ExportEXCEL" ohne Probleme. Das folgende Beispiel speichert eine ListView in eine Excel-Datei:
Delphi-Quellcode:
Leider kann man die Spaltenbreite nicht ändern.
procedure ExportDataToExcel(ExportFileName: string;
ExportListView: TListView); var XLSFile: TXLSExport; XLSFileName: string; ColumnsCount, ItemsCount, i, x, y: Integer; begin // Excel-Tabelle erstellen XLSFileName := ExportFileName; XLSFile := TXLSExport.Create(XLSFileName); if FileExists(XLSFileName) then DeleteFile(XLSFileName); try ColumnsCount := ExportListView.Columns.Count; ItemsCount := ExportListView.Items.Count; // Kopfzeilen for i := 0 to ColumnsCount -1 do XLSFile.Write(i, 0, ExportListView.Columns[i].Caption); // Daten y := 1; for i := 0 to ItemsCount -1 do begin XLSFile.Write(0, y, ExportListView.Items[i].Caption); for x := 0 to ColumnsCount -2 do XLSFile.Write(x + 1, y, ExportListView.Items[i].SubItems.Strings[x]); inc(y); end; finally end; XLSFile.Free; // Excel starten und Tabelle anzeigen if MessageDlg('Soll die Excel-Tabelle jetzt angezeigt werden?', mtConfirmation, [mbYes,mbNo], 0) = mrYes then try ShellExecute(0, nil, PChar(ExportFileName), nil, nil, SW_NORMAL); except MessageDlg('Excel-Programm konnte nicht gestartet werden!', mtError, [mbOk], 0); end; end; Gruß RoGa |
Re: Problem mit Excelexport
Hmm also ich habe auch nochmal ein bisschen rumprobiert und habe das jetzt so:
Delphi-Quellcode:
Mein Aufruf sieht so aus:
unit u_ExportEXCEL;
interface uses classes; type TXLSExport = class(TObject) private fs : TFilestream; CXlsBof : array[0..5] of Word; CXlsEof : array[0..1] of Word; CXlsLabel : array[0..5] of Word; CXlsNumber : array[0..4] of Word; CXlsRk : array[0..4] of Word; public constructor Create(filename : string); destructor Destroy; override; procedure Write(const Col, Row: Word; const Value: Integer); overload; procedure Write(const Col, Row: Word; const Value: Double); overload; procedure Write(const Col, Row: Word; const Value: string); overload; end; implementation constructor TXLSExport.Create(filename : string); begin inherited Create; fs := TFileStream.Create(filename,fmCreate); fs.WriteBuffer(CXlsBof, SizeOf(CXlsBof)); end; destructor TXLSExport.Destroy; begin fs.WriteBuffer(CXlsEof, SizeOf(CXlsEof)); inherited Destroy; end; procedure TXLSExport.Write(const Col, Row: Word; const Value: Integer); var V: Integer; begin CXlsRk[2] := Row; CXlsRk[3] := Col; fs.WriteBuffer(CXlsRk, SizeOf(CXlsRk)); V := (Value shl 2) or 2; fs.WriteBuffer(V, 4); end; procedure TXLSExport.Write(const Col, Row: Word; const Value: Double); begin CXlsNumber[2] := Row; CXlsNumber[3] := Col; fs.WriteBuffer(CXlsNumber, SizeOf(CXlsNumber)); fs.WriteBuffer(Value, 8); end; procedure TXLSExport.Write(const Col, Row: Word; const Value: string); var L: Word; begin L := Length(Value); CXlsLabel[1] := 8 + L; CXlsLabel[2] := Row; CXlsLabel[3] := Col; CXlsLabel[5] := L; fs.WriteBuffer(CXlsLabel, SizeOf(CXlsLabel)); fs.WriteBuffer(Pointer(Value)^, L); end; end.
Delphi-Quellcode:
Also es werden auch schon sachen in die Exceldatei geschrieben aber leider vollkommen unleserlicher kram wie z.B. 500 etc.
procedure TForm1.ExportierenExcel1Click(Sender: TObject);
var xf: TXLSExport; iCol, iRow: integer; Fields : TstringList; TempVal : String; begin VddQuery1.First; if not SaveDialog1.Execute then Exit; if FileExists(Savedialog1.Filename) then DeleteFile(SaveDialog1.Filename); xf := TXLSExport.Create(savedialog1.filename); Fields := TStringList.Create; VddQuery1.GetFieldNames(Fields); for iRow := 0 to VddQuery1.RecordCount - 1 do begin for iCol := 0 to Fields.Count - 1 do begin TempVal := VddQuery1.FieldByName(Fields[iCol]).AsString; xf.Write(iCol, iRow, TempVal); end; VddQuery1.Next; end; xf.Free; Fields.Free; end; Mir wird beim öffnen der .xls auch angezeigt das das Format der Datei nicht erkannt werden konnte :? Woran liegt das denn? :( mfg Alex |
Re: Problem mit Excelexport
Hallo Borschti,
zu Deiner Eingangsfrage:
Delphi-Quellcode:
Wenn Auf dem Rechner kein excel installiert ist, dann bekommst Du eine Fehlermeldung.
excel : variant;
begin try excel:=createoleobject('EXCEL.APPLICATION'); except showmessage('Excel kann nicht gestartet werden!'); exit; end; Wenn Du unbedingt eine Ausgabe erstellen willst oder mußt, dann nimm doch CSV . Deine letzte Frage von hinten aufgedröselt: Wenn Das excel auf Deinem Rechner das Dateiformat nicht richtig erkennen kann, dann ist es entweder zickig oder aber es kennt das Format nicht. In beiden Fällen sollte die Datenanzeige nicht sehr zuverlässig sein. Da ich nicht die vollständige Unit gesehen habe mit der Du arbeitest, kann ich wenig konkretes hierzu sagen, aber die excel-Dateien, die auf meinem Rechner liegen, können damit nicht erstellt werden. Ansonsten kann ich Dir nur den Tip geben die Erstellungsroutine mit bekannten Daten zu testen. Bekannt heißt "im Programm generiert" und nicht über irgendeine obskure Query irgendwoher geholt. Gruß K-H |
Re: Problem mit Excelexport
Erstmal danke für die Tipps, also die Datenmenge welche sich in der Query befindet ist zu 100% in Ordnung, in meiner ersten Prozedur wurde alles korrekt an Excel übergeben :)
Hier ist mal die komplette Unit zum besseren Verständniss:
Delphi-Quellcode:
Benutzen tue ich Excel 2003.
unit ExcStat;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, VisiButton, Grids, DBGrids, VisiDbGrid, DB, vddDataSource, vddDataSet, vddReferenceDataSet, vddCustomQuery, vddQuery, l_treiberinit, comctrls, DBClient, ComObj, OleServer, ExcelXP, VisiOpenDialog, Menus, u_ExportEXCEL; type TForm1 = class(TForm) VddQuery1: TVddQuery; VddDataSource1: TVddDataSource; VisiDbGrid1: TVisiDbGrid; VisiButton1: TVisiButton; ExcelApplication1: TExcelApplication; ExcelWorksheet1: TExcelWorksheet; ExcelWorkbook1: TExcelWorkbook; SaveDialog1: TSaveDialog; PopupMenu1: TPopupMenu; ExportierenExcel1: TMenuItem; procedure FormCreate(Sender: TObject); procedure VisiButton1Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure ExportierenExcel1Click(Sender: TObject); private { Private-Deklarationen } public { Public-Deklarationen } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.ExportierenExcel1Click(Sender: TObject); var xf: TXLSExport; iCol, iRow: integer; Fields : TstringList; TempVal : String; begin VddQuery1.First; if not SaveDialog1.Execute then Exit; if FileExists(Savedialog1.Filename) then DeleteFile(SaveDialog1.Filename); xf := TXLSExport.Create(savedialog1.filename); Fields := TStringList.Create; VddQuery1.GetFieldNames(Fields); for iRow := 0 to VddQuery1.RecordCount - 1 do begin for iCol := 0 to Fields.Count - 1 do begin TempVal := VddQuery1.FieldByName(Fields[iCol]).AsString; xf.Write(iCol, iRow, TempVal); end; VddQuery1.Next; end; xf.Free; Fields.Free; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin //ExcelApplication1.Quit; //ExcelApplication1.Disconnect; end; procedure TForm1.FormCreate(Sender: TObject); begin Treibermodule.LogInDialog.Execute; end; procedure TForm1.VisiButton1Click(Sender: TObject); var SQL : String; begin VddQuery1.Close; VddQuery1.SQL.Clear; SQL := 'delete from K_staadr; insert into K_staadr(adrNr) select adrNr from adress where adress.adrgr = '+quotedStr('K')+';'; SQL := SQL + ' update K_STAADR set k_staadr.vk_vj=staadr.vk,k_staadr.roh_vj=staadr.roh from K_staadr inner join staadr on k_staadr.adrnr = staadr.adrnr where staadr.jahr=2007 and staadr.monat=13;'; SQL := SQL + ' update K_STAADR set k_staadr.vk_lj=staadr.vk,k_staadr.roh_lj=staadr.roh from K_staadr inner join staadr on k_staadr.adrnr = staadr.adrnr where staadr.jahr=2008 and staadr.monat=13;'; SQL := SQL + ' select adress.adrnr,adress.adrgr,adress.name1,adress.name2, adress.plz, adress.ort, adress.strasse, K_staadr.vk_vj,K_staadr.roh_vj,K_staadr.vk_lj, K_staadr.roh_lj from adress left outer join K_staadr on adress.adrnr = K_staadr.adrnr'; VddQuery1.SQL.Add(SQL); VddQuery1.Open; end; end. Ich hoffe das es jetzt verständlicher ist. Also das mit den CSV Dateien, wie funktioniert das genau? Ich muss doch erst meine Daten in eine CSV Datei Speichern und diese Datei dann in Excel einlesen oder? Hat hierfür vielleicht jemand ein Codebeispiel oder einen Tipp wie ich damit anfangn könnte? mfg Alex Edit: Also habe mir nochmal den Thread, der bei der Suche rauskam, angeguckt und mir ist aufgefallen das Bernhard Geyer schrieb das der ausgewählte Font diese Kästchen verursachen kann, also der Font muss Unicodefähig sein. Ich will mal probieren ob das wirklich was bringt und ich stelle mir grade die Frage wie ich den Font wohl ändern könnte. Weiß da vielleicht jemand rat? mfg Alex |
Re: Problem mit Excelexport
Hallo Borschi,
Delphi-Quellcode:
type TXLSExport = class(TObject)
private fs : TFilestream; CXlsBof : array[0..5] of Word; CXlsEof : array[0..1] of Word; CXlsLabel : array[0..5] of Word; CXlsNumber : array[0..4] of Word; CXlsRk : array[0..4] of Word; public Zitat:
Du hast vergessen die Konstanten für das Biff-Format einzutragen, jetzt werden die Daten nicht im XLS-Format gespeichert, sonder als Text-Datei mit Stringlängen Angabe. Vielleicht Testes Du das mit folgender Procedure in der CodLib. Da wird zwar ein StringGrid in XLS-Datei abgespeichert, aber es dürfte nicht so schwer sein das auf Deine Anforderungen umzuschreiben. ![]() Bis bald Chemiker |
Re: Problem mit Excelexport
Hallo Borschti,
CSV ist auch als ASCII-Delimited bekannt, Dazu gibt es auch eine RFC aber die kann ich gerade nicht finden. Ganz knapp formuliert funktioniert das so: Die Datei ist eine Textdatei. Für jeden Datensatz gibt es einen Zeile.
Delphi-Quellcode:
Rein theoretisch ist der Feldbegrenzer " nur notwendig wenn das Trennzeichen im Feld vorkommt. Bei neueren Datenbeständen ist aber praktisch jedes Feld mit Begrenzern versehen.
Daten+CRLF / Daten +LF { Trenner ist #13#10 oder #10}
Daten=Feld+[Trennzeichen]+Feld+[TrennZeichen]+Feld....... { Trennzeichen kann beliebig definiert werden excl. CR und LF } Feld=["]+[Bstb]/[Zahl]/[SonderZchn]....+["] Falls Du nur numerische Werte übergeben willt ist aber auch so etwas zulässig: 1234,12.4,400 ... usw. oder 1234;12.4;400 ... usw. oder 1234;12,4;400 ... usw. Im Jedi-Projekt soll es übrigens Routinen für die CSV-Verarbeitung geben. Ausserdem hat Tstrings auch etwas zu bieten: Zitat:
Das Auslesen aus einer DB geht ungefähr so
Delphi-Quellcode:
Bitte verwende den Schnipsel nicht ungeprüft, da fehlt die Initialisierung und die Finalisierung von Dummy, da geht's nur ums Prinzip
repeat
for i:=0 to dm_portfolio.mquery1.fields.count-1 do dummy:=dummy+trenner+dm_portfolio.mquery1.fields.fields[i].asstring; ll.add(dummy); dummy:=''; dm_portfolio.mquery1.next; until dm_portfolio.mquery1.eof; Gruß K-H |
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:05 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz