Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Problem mit Excelexport (https://www.delphipraxis.net/117459-problem-mit-excelexport.html)

Borschti 18. Jul 2008 13:49


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:
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;
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. :)

Also dann ich hoffe ihr könnt mir weiterhelfen.

mfg
Alex

ralfschwalbe 18. Jul 2008 14:25

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;

Borschti 18. Jul 2008 14:33

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.

Union 18. Jul 2008 15:11

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.

roga 18. Jul 2008 22:32

Re: Problem mit Excelexport
 
Hallo Borschti,

suche bitte mal nach Hier im Forum suchenTXLSExport, da gehts auch ohne installiertes Excel.

Gruß RoGa

Apollonius 18. Jul 2008 22:41

Re: Problem mit Excelexport
 
Nebenbei bemerkt: CreateFile gibt ein Handle zurück, das man schließen sollte.

Borschti 21. Jul 2008 09:18

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 Thread gestoßen.

Hier habe ich mir diese Unit kopiert:

Delphi-Quellcode:
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.
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.

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

roga 21. Jul 2008 09:39

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:
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;
Leider kann man die Spaltenbreite nicht ändern.

Gruß RoGa

Borschti 21. Jul 2008 10:18

Re: Problem mit Excelexport
 
Hmm also ich habe auch nochmal ein bisschen rumprobiert und habe das jetzt so:

Delphi-Quellcode:
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.
Mein Aufruf sieht so aus:

Delphi-Quellcode:
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;
Also es werden auch schon sachen in die Exceldatei geschrieben aber leider vollkommen unleserlicher kram wie z.B. 500 etc.

Mir wird beim öffnen der .xls auch angezeigt das das Format der Datei nicht erkannt werden konnte :?

Woran liegt das denn? :(

mfg
Alex

p80286 21. Jul 2008 11:00

Re: Problem mit Excelexport
 
Hallo Borschti,

zu Deiner Eingangsfrage:

Delphi-Quellcode:
  excel : variant;
   
begin
  try
    excel:=createoleobject('EXCEL.APPLICATION');
  except
    showmessage('Excel kann nicht gestartet werden!');
    exit;
  end;
Wenn Auf dem Rechner kein excel installiert ist, dann bekommst Du eine Fehlermeldung.
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


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:43 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz