Home » Tipps & Tricks » Komponenten » TStringGrid » StringGrid-Inhalt nach Excel exportieren

StringGrid-Inhalt nach Excel exportieren

Oft kommt es vor, dass Daten, die in einer eigenen Anwendung verwaltet werden, zusammengefasst und ausgewertet werden sollen. Dazu bietet sich die Verwendung von Standardsoftware wie Excel an. Excel bietet hierzu eine Schnittstelle zur Automatisierung an. Details können auch im Tutorial OLE-Automation von MS Office nachgelesen werden.Folgendes Code-Beispiel exportiert den Inhalt eines StringGrids in ein Excel-Sheet.

uses 
  ComObj, Math, SysUtils, Variants;

//Hilfsfunktionen
function StringToVariant(const SourceString : string) : Variant;
var
  FloatValue : Extended;
begin
  if TryStrToFloat(SourceString, FloatValue) then
    Result := FloatValue
  else
    Result := SourceString;
end;

function RefToCell(Col, Row : Integer) : string;
var
  Pos : Integer;
begin
  //Spalte bestimmen
  Result := '';
  while Col > 0 do
  begin
    Pos := Col mod 26;
    if Pos = 0 then
    begin
      Pos := 26;
      Dec(Col);
    end;
    Result := Chr(Ord('A') + Pos - 1) + Result;
    Col := Col div 26;
  end;
  //Spalte und Zeile zusammenführen
  Result := Result + IntToStr(Row);
end;

//Inhalt eines TStringGrid nach Excel exportieren und anzeigen
function ExportStringGridToExcel(StringGrid : TStringGrid) : Boolean;
var
  Col       : Integer;
  Data      : OleVariant;
  ExcelApp  : OleVariant;
  MaxCol    : Integer;
  MaxRow    : Integer;
  Range     : OleVariant;
  Row       : Integer;
  Workbook  : OleVariant;
  Worksheet : OleVariant;
  Value     : OleVariant;
begin
  Result := False;
  //Verbindung zu Excel herstellen
  ExcelApp := CreateOleObject('Excel.Application');
  try
    if not VarIsNull(ExcelApp) then
    begin
      //Neues Workbook öffnen
      Workbook := ExcelApp.Workbooks.Add;
      if not VarIsNull(Workbook) then
      begin
        //Maximalen Bereich bestimmen
        MaxCol := Min(StringGrid.ColCount, ExcelApp.Columns.Count);
        MaxRow := Min(StringGrid.RowCount, ExcelApp.Rows.Count);
        if (MaxRow > 0) and (MaxCol > 0) then
        begin
          //Worksheet auswählen
          Worksheet := Workbook.ActiveSheet;
          //Bereich auswählen
          Range := Worksheet.Range[RefToCell(1, 1), RefToCell(MaxCol, MaxRow)];
          if not VarIsNull(Range) then
          begin
            //Daten aus Grid holen
            Data := VarArrayCreate([1, MaxRow, 1, MaxCol], varVariant);
            for Row := 0 to Pred(MaxRow) do
            begin
              for Col := 0 to Pred(MaxCol) do
              begin
                Value := StringToVariant(StringGrid.Cells[Col, Row]);
                Data[Succ(Row), Succ(Col)] := Value
              end;
            end;
            //Daten dem Excelsheet übergeben
            Range.Value := Data;
            Range.Columns.AutoFit;
            //Excel anzeigen
            Workbook.Activate;
            ExcelApp.Visible := True;
            Result := True;
          end;
        end;
      end;
    end;
  finally
    Value    := UnAssigned;
    Data     := UnAssigned;
    Range    := UnAssigned;
    Workbook := UnAssigned;
    ExcelApp := UnAssigned;
  end;
end;

Ein Worksheet kann je nach Excel-Programmversion nur eine bestimmte Anzahl von Spalten und Zeilen aufnehmen. Deshalb kann es erforderlich sein, dass die Daten des TStringGrid auf mehrere Workbooks und Worksheets aufgeteilt werden müssen. Wie das funktionieren kann, zeigt das folgende Code-Beispiel.

//Inhalt eines TStringGrid in Excel-Dateien speichern
function WriteStringGridToExcelFiles(StringGrid : TStringGrid;
                                     const Directory : string) : Boolean;
var
  Col            : Integer;
  Data           : OleVariant;
  ExcelApp       : OleVariant;
  FileName       : string;
  GridCol        : Integer;
  GridRow        : Integer;
  MaxCol         : Integer;
  MaxRow         : Integer;
  Range          : OleVariant;
  Row            : Integer;
  Value          : OleVariant;

  Workbook       : OleVariant;
  WorkbookCount  : Integer;
  WorkbookIndex  : Integer;
  Worksheet      : OleVariant;
  WorksheetCount : Integer;
  WorksheetIndex : Integer;
begin
  Result := False;
  //Verbindung zu Excel herstellen
  ExcelApp := CreateOleObject('Excel.Application');
  try
    if not VarIsNull(ExcelApp) then
    begin
      Result := True;
      //Maximalen Bereich bestimmen
      Workbook := ExcelApp.Workbooks.Add;
      MaxCol := Min(StringGrid.ColCount, ExcelApp.Columns.Count);
      MaxRow := Min(StringGrid.RowCount, ExcelApp.Rows.Count);
      Workbook.Close;
      //Anzahl Worksheets und Workbooks bestimmen
      WorkbookCount := (StringGrid.RowCount div MaxRow);
      if StringGrid.RowCount mod MaxRow > 0 then
        Inc(WorkbookCount);
      WorksheetCount := (StringGrid.ColCount div MaxCol);
      if StringGrid.ColCount mod MaxCol > 0 then
        Inc(WorkbookCount);
      //Variantes Array zur Datenübergabe erstellen
      Data := VarArrayCreate([1, MaxRow, 1, MaxCol], varVariant);
      for WorkbookIndex := 0 to Pred(WorkbookCount) do
      begin
        //Neues Workbook öffnen
        Workbook := ExcelApp.Workbooks.Add;
        if not VarIsNull(Workbook) then
        begin
          //überzählige Worksheets entfernen
          while Workbook.Sheets.Count > 1 do
            WorkBook.Sheets.Delete;

          for WorksheetIndex := 0 to Pred(WorksheetCount) do
          begin
            //Neues Worksheet öffnen
            if WorkSheetIndex = 0 then
              WorkSheet := Workbook.ActiveSheet
            else
              Worksheet := Workbook.Sheets.Add(After := Workbook.ActiveSheet);
            if not VarIsNull(Worksheet) then
            begin
              //Bereich auswählen
              Range := Worksheet.Range[RefToCell(1, 1),
                                       RefToCell(MaxCol, MaxRow)];
              if not VarIsNull(Range) then
              begin
                //Daten aus Grid holen
                for Row := 0 to Pred(MaxRow) do
                begin
                  for Col := 0 to Pred(MaxCol) do
                  begin
                    GridCol := Col + (MaxCol * WorksheetIndex);
                    GridRow := Row + (MaxRow * WorkbookIndex);
                    if (GridCol < StringGrid.ColCount) and
                       (GridRow < StringGrid.RowCount) then
                    begin
                      Value := StringToVariant(StringGrid.Cells[GridCol,
                                                                GridRow]);
                      Data[Succ(Row), Succ(Col)] := Value;
                    end
                    else
                      Data[Succ(Row), Succ(Col)] := '';
                  end;
                end;
                //Daten dem Excelsheet übergeben
                Range.Value := Data;
                Range.Columns.AutoFit;
              end;
            end;
          end;
        end;
        //Workbook schließen und speichern
        FileName := Format('%s%.2d', [StringGrid.Name, Succ(WorkbookIndex)]);
        FileName := Directory + FileName;
        Workbook.Close(SaveChanges := True, Filename := FileName);
        Result := Result and
                  (FileExists(FileName + '.xls') or
                   FileExists(FileName + '.xlsx'));
      end;
      //Excel beenden
      ExcelApp.DisplayAlerts := False;
      ExcelApp.Quit;
    end;
  finally
    Value     := UnAssigned;
    Data      := UnAssigned;
    Range     := UnAssigned;
    Workbook  := UnAssigned;
    Worksheet := UnAssigned;
    ExcelApp  := UnAssigned;
  end;
end;
procedure TTestDialog.ExportButtonClick(Sender: TObject);
begin
  ExportStringGridToExcel(DataStringGrid);
end;

procedure TTestDialog.SaveButtonClick(Sender: TObject);
begin
  if WriteStringGridToExcelFiles(DataStringGrid, 'C:Test') then
    MessageDlg('Tabelle wurde gespeichert.', mtInformation, [mbOk], 0)
  else
    MessageDlg('Tabelle konnte nicht gespeichert werden', mtError, [mbOk], 0);
end;

Weitere Informationen zur OLE-Automation von Excel können auch im Tipp Excel mit OLE-Automation steuern nachgelesen werden.