StringGrid schneller (virtual) Export in Excel/Libre Office - Probleme wenn FixedCols = 1 (Anzeige Zeilennummern)

Rund um die LCL und andere Komponenten
Antworten
Helios
Lazarusforum e. V.
Beiträge: 107
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.6 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

StringGrid schneller (virtual) Export in Excel/Libre Office - Probleme wenn FixedCols = 1 (Anzeige Zeilennummern)

Beitrag von Helios »

Hallo Zusammen,

bei dem Thema viewtopic.php?f=18&t=13803 hatte ich freundlicherweise ein Beispielprogramm GridToXLSX.zip erhalten,
mit dem ich den Inhalt eines Grids sehr zügig (virtual Mode) in eine Excel (XLSX) oder Libre/Open Office (ODS) Datei speichern kann (prima Feature, vielen Dank dafür noch einmal)!
Das StringGrid verwende ich u.A. auch deswegen, weil man sich die Zeilennummer im Grid anzeigen kann (Options goFixedRowNumbering := True).
Dazu muss aber im Grid FixedCols auf 1 gesetzt werden und dann laufe ich in eine Fehlermeldung "List Index out of Bounds" sobald ich den XLSX bzw. ODS Export starte.
Ich habe nun schon einige Einstellungen mit den FixedCols (bzw. die Colums um 1 erweitert) usw. ausprobiert, entweder laufe ich in den oben genannten Fehler,
oder die Ausgabe wird um eine Spalte verschoben etc.

Hat jemand eine Idee wie man es richtig macht und Zeilennummern im Grid angezeigt bekommt?
Beispielprojekt siehe Anhang. Um den Fehler zu reproduzieren muss dafür noch im Grid FixedCols := 1 gesetzt, ein paar Beispieldaten/-zeilen mit "Start" generiert
und der XLSX oder ODS Export gestartet werden.

Danke und Gruß

Helios
Dateianhänge
GridToXLSX2.zip
(66.55 KiB) 49-mal heruntergeladen

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: StringGrid schneller (virtual) Export in Excel/Libre Office - Probleme wenn FixedCols = 1 (Anzeige Zeilennummern)

Beitrag von wp_xyz »

Man kann TStringGrid in zwei Arten betreiben: als "normale" Tabelle, in der jede Zelle durch eine Zeile- und Spaltenindex gefunden wird, so wie in Delphi, oder als Tabelle mit vordefinierten "Spalten" (Columns) - das ist etwas komfortabler, macht aber die Spalten-Indizierung komplizierter. Eine leeres Grid ohne Columns hat die FixedCol mit Index 0. Fügt man mit Columns.Add eine Spalte hinzu, hat diese in der Columns-Collection den Index 0, aber als Grid-Spalte den Index 1. Die beiden Arten von Indices unterscheiden sich also um die Zahl der FixedCols.

Darin steckt dein Hauptproblem. Denn dem OnWriteCellData-Ereignis werden die Grid-Indices mitgegeben. In dem Fall "if ARow = 0", also wenn die Titelzeile ausgelesen wird, holst du den Zell-Text über "StringGrid.Columns[ACol].Title.Caption". ACol ist da aber als Grid-Spaltenindex gemeint, den du hier als Index in der Columns-Collection verwendest. Du musst also von ACol den Wert von StringGrid.FixedCols abziehen, um die richtige Spalte in der Columns-Collection zu finden.

Code: Alles auswählen

  AData := StringGrid.Columns[ACol - StringGrid.FixedCols].Title.Caption;
Da gibt es noch ein Problem in der FixedCol, denn ACol ist dann 0, und wenn man StringGrid.FixedCols subtrahiert, hat man als Index von Columns den Wert -1, was dir wieder einen Index-Fehler beschert. Daher noch eine Fallunterscheidung... Insgesamt hätten wir nun:

Code: Alles auswählen

procedure TFrame1.WriteCellDataHandler(Sender: TsWorksheet; ARow, ACol: Cardinal; var AData: variant; var AStyleCell: PCell);
begin
  if (ACol = 0) and (ARow = 0) then
    AData := ''
  else
  if ARow = 0 then
    AData := StringGrid.Columns[ACol-StringGrid.FixedCols].Title.Caption   // Achtung: das wird -1 wenn ACol=0 and StringGrid.FixedCols>0 ist!!!
  else
    AData := StringGrid.Cells[ACol, ARow];
end;
Dass die FixedCol exportiert wird (sie wird hier leer), kann man nicht verhindern, aber wenn du das nicht willst, musst du die erzeugte Spreadsheetdatei nach dem Export in ein Workbook laden, die 1.Spalte löschen und erneut speichern.

Helios
Lazarusforum e. V.
Beiträge: 107
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.6 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: StringGrid schneller (virtual) Export in Excel/Libre Office - Probleme wenn FixedCols = 1 (Anzeige Zeilennummern)

Beitrag von Helios »

Hallo wp_xyz,
vielen Dank für Deine Rückmeldung.
Diese unterschiedliche Indizierung und die Probleme, die sich dadurch ergeben hatte ich noch nicht richtig scharfgestellt.
Ich muss noch etwas mit den Einstellungen herumspielen, denn bei FixedCols = 0 fehlt mir nun die 1. Spaltenüberschrift "No.", aber im Falle FixedCols = 1 ist der Laufzeitfehler wie von Dir beschrieben/umgesetzt weg
(siehe neue Version im Anhang).

Es ist nicht möglich die (statischen) Zeilennummern in das XLSX Worksheet zu übernehmen, oder?
Sprich die (statischen) Zeilennummern im Visuellen Grid sind nicht z.B. über StringGrid.Cells[Spalte, Zeile] erreichbar, oder täusche ich mich da?

Gruß
Helios
Dateianhänge
GridToXLSX2_Vers2.zip
(195.88 KiB) 48-mal heruntergeladen

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: StringGrid schneller (virtual) Export in Excel/Libre Office - Probleme wenn FixedCols = 1 (Anzeige Zeilennummern)

Beitrag von wp_xyz »

Helios hat geschrieben:
Mi 20. Okt 2021, 10:48
Es ist nicht möglich die (statischen) Zeilennummern in das XLSX Worksheet zu übernehmen, oder?
Sprich die (statischen) Zeilennummern im Visuellen Grid sind nicht z.B. über StringGrid.Cells[Spalte, Zeile] erreichbar, oder täusche ich mich da?
Diese Zeilennummern in der FixedCol sind nicht Bestandteil des Grid, sondern entsprechen dem Zeilenindex, der dem Grid sowieso bekannt sein muss. Wenn du z.B. eine Zeile löschst, gehen die Zeilennummern an der Löschstelle nahtlos weiter. Wären sie im Grid gespeichert, würde man einen Sprung um 1 sehen.

Wenn du die Zeilennummer im Worksheet haben willst, musst du die Datei nach dem Export in ein TsWorkbook laden und die Werte in die ohnehin leere 1. Spalte schreiben. Ohne Test:

Code: Alles auswählen

var
  workbook: TsWorkbook;
  worksheet: TsWorksheet;
begin
  // ... Export in die Datei 'FileName.xlsx', 1. Worksheet ....
  // Dann:
  workbook := TsWorkbook.Create;
  try
    workbook.ReadFromFile('FileName.xlsx');
    worksheet := workbook.GetFirstWorksheet;
    for r := 0 to worksheet.GetLastRowIndex do
      worksheet.WriteNumber(r, 0, r+1);
    workbook.WriteToFile('Filename.xlsx', true);
  finally
    workbook.Free;
  end;

Helios
Lazarusforum e. V.
Beiträge: 107
Registriert: Mi 29. Jun 2011, 22:36
OS, Lazarus, FPC: Lazarus 2.2.6 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
CPU-Target: 64Bit
Wohnort: Leonberg

Re: StringGrid schneller (virtual) Export in Excel/Libre Office - Probleme wenn FixedCols = 1 (Anzeige Zeilennummern)

Beitrag von Helios »

Hallo wp_xyz,
erneut besten Dank.
Du kennst ja vielleicht noch meine Anforderungen (ca. 1Mio Zeilen (readonly) im Grid).
Ich glaube da ist es dann besser ich erzeuge meine Zeilennummerspalte (analog "No.") jeweils immer selbst,
dann habe ich beim einmaligen Speichern auch die Zeilennummern im Sack/bzw. in der Datei.
Mit meinem Wunsch die Zeilennummern über das Grid zu generieren habe ich einfach zu viele Zustände die es zu berücksichtigen gilt. Das Verändern eines Worksheets über workbook.GetFirstWorksheet/worksheet.GetLastRowIndex kannte ich aber noch nicht und wird sicher bald zum Einsatz kommen.
Was ist eigentlich das StringGrid.Cells[ACol, ARow] für ein Datentyp? Ist das ein ganz normales 2 dimensionales Array of Strings. So richtig schlau aus der Referenz bin ich da noch nicht geworden. Ich schätze das muss ich mir im Code anschauen (in der Hoffnung, dass ich es da auch verstehe:-))
Danke erneut für Deine Tipps und schönen Abend.
Helios

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: StringGrid schneller (virtual) Export in Excel/Libre Office - Probleme wenn FixedCols = 1 (Anzeige Zeilennummern)

Beitrag von wp_xyz »

Helios hat geschrieben:
Mi 20. Okt 2021, 17:54
Was ist eigentlich das StringGrid.Cells[ACol, ARow] für ein Datentyp?
String

Antworten