![]() |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Folgendes wäre der aktuell komplette Code, der mit Excel was zu tun hat. Das Problem tritt nur beim
Delphi-Quellcode:
auf, dies scheint bei einer xml somit nicht zu funktionieren, da brauche ich eine Alternative:
Workbook.saveas(AXLSFile, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, False, EmptyParam, EmptyParam, GetUserDefaultLCID);
Delphi-Quellcode:
unit Toolbox;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ComCtrls, Vcl.Grids, IniFiles, Vcl.FileCtrl, shellapi, ComObj, Vcl.ExtCtrls, Math, System.UITypes, Vcl.WinXCtrls, directorywatch; type TTools = class(TForm) //... procedure FormCreate(Sender: TObject); procedure AbbrechenClick(Sender: TObject); procedure SpeichernEClick(Sender: TObject); Procedure FindDirs(DirPath: String; StringList:TStrings; Recurse: Boolean = false); procedure ProgramsClick(Sender: TObject); Procedure ListFiles(Box : TListbox); procedure ProgramsDblClick(Sender: TObject); procedure DataDblClick(Sender: TObject); function Split(text: string; delimiter: char; p: integer): string; procedure ManuellClick(Sender: TObject); procedure SuchePBClick(Sender: TObject); function CopyDir(SourceDirectory: string; DestinationDirectory: string): boolean; procedure KopierenClick(Sender: TObject); function Delete(const AFile: string): boolean; procedure FertigClick(Sender: TObject); function GetCurrentUserName: string; function Xls_To_StringGrid(AGrid: TStringGrid; Sheetname : string): Boolean; procedure EinlesenFClick(Sender: TObject); procedure GridColWidth(grd:TStringGrid;min,max:word); procedure SucheFBClick(Sender: TObject); procedure XLS_ManuellClick(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure DE_XLSClick(Sender: TObject); procedure SucheFEClick(Sender: TObject); procedure SuchePEClick(Sender: TObject); function StringgridToXLS(StringGrid : TStringGrid; sheetname : String) : Boolean; procedure SpeichernFClick(Sender: TObject); procedure SucheFEChange(Sender: TObject); procedure SuchePEChange(Sender: TObject); function RefToCell(Col, Row : Integer) : string; function StringToVariant(const SourceString : string) : Variant; function FindStrAndCount(const TargetString, Symbol: String): Integer; procedure LogListClick(Sender: TObject); procedure FilialenPSClick(Sender: TObject); procedure FilialStartChange(Sender: TObject); procedure FilialEndeEnter(Sender: TObject); procedure FilialStartClick(Sender: TObject); procedure NewLog(Path : string); procedure Timer3Timer(Sender: TObject); function ReportFileTimes(const FileName: string) : TDateTime; procedure LogEinlesenClick(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormDestroy(Sender: TObject); private { Private-Deklarationen } Watch: TDirectoryWatch; procedure OnNotify(const Sender: TObject; const Action: TWatchAction; const FileName: string); public { Public-Deklarationen } end; var Tools : TTools; FileAction, LogName, LogDatei: String; olddate, newdate, FileChange : TDateTime; XLApp : OleVariant; implementation {$R *.dfm} //Excel bei Programmende schließen procedure TTools.FormClose(Sender: TObject; var Action: TCloseAction); begin if not VarIsEmpty(XLApp) then begin XLApp.DisplayAlerts := false; XLApp.Quit; XLAPP := Unassigned; end; end; //Grundeinstellungen laden procedure TTools.FormCreate(Sender: TObject); var Ini: TIniFile; begin Ini:=TIniFile.Create(ExtractFilePath(ParamStr(0)) + '\Settings.ini'); try InstallE.Text := Ini.ReadString('Install', 'Ordner', 'nicht festgelegt!'); ExcelE.Text := Ini.ReadString('Install', 'Excel', 'nicht festgelegt!'); OriginalE.Text := Ini.ReadString('Install', 'Originale', 'nicht festgelegt!'); DataEC.Checked := Ini.ReadBool('Checkbox', 'Daten', False); LogEC.Checked := Ini.ReadBool('Checkbox', 'Log', False); ErgebnisEC.Checked:= Ini.ReadBool('Checkbox', 'Ergebnis', False); ExcelC.Checked := Ini.ReadBool('Checkbox', 'Excel', False); FertigEC.Checked := Ini.ReadBool('Checkbox', 'Fertig', False); DatenC.Checked := DataEC.Checked; LogC.Checked := LogEC.Checked; ErgebnisC.Checked := ErgebnisEC.Checked; FertigC.Checked := FertigEC.Checked; KopierenE.Text := InstallE.Text; finally Ini.Free; end; // Create Excel-OLE Object XLApp := CreateOleObject('Excel.Application'); XLApp.Visible := False; XLApp.Workbooks.OpenXML(ExcelE.text); //Logdatei einlesen LogList.Items.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'Log.txt'); //Programm zum arbeiten vorbereiten FindDirs(OriginalE.Text,Programs.Items); if ExcelC.Checked = true then EinlesenFClick(Sender); ExcelSheets.Pages[0].Show; Menu.Pages[1].Show; end; //Excel bei Programmabsturz schließen procedure TTools.FormDestroy(Sender: TObject); begin if not VarIsEmpty(XLApp) then begin XLApp.DisplayAlerts := false; XLApp.Quit; XLAPP := Unassigned; end; end; //Excel in ein Stringgrid übertragen function TTools.Xls_To_StringGrid(AGrid: TStringGrid; Sheetname : string): Boolean; const xlCellTypeLastCell = $0000000B; var Sheet: OLEVariant; RangeMatrix: Variant; x, y, k, r: Integer; begin Result := False; x := 0; y := 0; try Sheet := XLApp.Workbooks[ExtractFileName(ExcelE.text)].WorkSheets[sheetname]; // In order to know the dimension of the WorkSheet, i.e the number of rows // and the number of columns, we activate the last non-empty cell of it XLApp.Workbooks[ExtractFileName(ExcelE.text)].WorkSheets[sheetname].select; Sheet.Cells.SpecialCells(xlCellTypeLastCell, EmptyParam).Activate; x := XLApp.ActiveCell.Row; // Get the value of the last row y := XLApp.ActiveCell.Column; // Get the value of the last column // Set Stringgrid's row &col dimensions. AGrid.RowCount := x + 4; AGrid.ColCount := y; RangeMatrix := XLApp.Range['A1', XLApp.Cells.Item[X, Y]].Value; // Assign the Variant associated with the WorkSheet to the Delphi Variant // Define the loop for filling in the TStringGrid k := 1; repeat for r := 1 to y do AGrid.Cells[(r - 1), (k - 1)] := RangeMatrix[K, R]; Inc(k, 1); AGrid.RowCount := k + 1; until k > x; // Unassign the Delphi Variant Matrix RangeMatrix := Unassigned; finally // Quit Excel if not VarIsEmpty(XLApp) then begin XLApp.DisplayAlerts := false; Sheet := Unassigned; Result := True; end; end; end; //Inhalt eines TStringGrid nach Excel exportieren function TTools.StringgridToXLS(StringGrid : TStringGrid; sheetname : String) : Boolean; var Col : Integer; Data : OleVariant; MaxCol : Integer; MaxRow : Integer; Range : OleVariant; Row : Integer; Workbook : OleVariant; Worksheet : OleVariant; Value : OleVariant; begin Result := False; //Verbindung zu Excel herstellen try if not VarIsNull(XLApp) then begin //Workbook öffnen XLApp.Workbooks.OpenXML(ExcelE.Text); if not VarIsNull(Workbook) then begin //Maximalen Bereich bestimmen MaxCol := Min(StringGrid.ColCount, XLApp.Workbooks[ExtractFileName(ExcelE.Text)].WorkSheets[sheetname].Columns.Count); MaxRow := Min(StringGrid.RowCount, XLApp.Workbooks[ExtractFileName(ExcelE.Text)].WorkSheets[sheetname].Rows.Count); if (MaxRow > 0) and (MaxCol > 0) then begin //Worksheet auswählen Worksheet := XLApp.Workbooks[ExtractFileName(ExcelE.Text)].WorkSheets[sheetname]; //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; Result := True; end; end; end; end; finally if not VarIsEmpty(XLApp) then begin XLApp.DisplayAlerts := False; Workbook.saveas(ExcelE.Text, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, False, EmptyParam, EmptyParam, GetUserDefaultLCID); Value := UnAssigned; Data := UnAssigned; Range := UnAssigned; Workbook := UnAssigned; end; end; end; |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Was mir mMn auf die Schnelle aufgefallen ist:
Sowohl im Form.Create als auch in StringgridToXLS öffnest du jeweils die Datei. Einmal müsste doch eigentlich reichen? Edit: Was man auch immer mal versuchen könnte: Visible und DisplayAlerts auf True setzen, dann sieht man wenigstens, was den Excel zu mecker hat. |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Excel selber hat gar nichts angezeigt.
Das mit dem 2'öffnen habe ich ich korrigiert. Auch Ist mir aufgefallen, das Workbooks wieder kein wert zugewiesen wurde und dies geändert. nun bekomme ich den Hinweis, das "saveas" vom automatisierungsobjekt nicht unterstützt wird. -.- |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Liste der Anhänge anzeigen (Anzahl: 1)
Hmm..
Um das hier mal abzukürzen... Ein kleines Beispiel, basierend auf deinem Code, jedoch alle Excel-Sachen in eigene Unit verfrachtet und deutlich aufgeräumt.. ;) In dem Beispiel wird ein Excel-Dokument (OpenDialog) geöffnet und das angegeben Sheet ein das Grid eingelesen. Hierbei wird angenommen, das die erste ROW im Excel-Dokument die Header-Zeile ist. (Musterdatei beigelegt) Beim Speichern werden die Daten aus dem Grid ins Excel-Dokument geschrieben und dieses gespeichert. Das eigentliche Schließen von Excel erfolgt erst im OnClose des Formulares. (Erstellt mit D6) |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Auch mit deiner Unit habe ich nun das Problem, das er die Zellinhalte der Worksheets durcheinander schmeißt. Das hatte ich zwischenzeitlich auch, weiß aber aktuell nicht woran es liegt.
Das Problem mit der Namensgebung lag an der Excel und konnte ich beheben. |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Liste der Anhänge anzeigen (Anzahl: 1)
Ähm... mal ne simple Frage: Wieso nicht einfach das StringGrid als CSV speichern?
Das lässt sich in Excel problemlos (sogar problemloser als XLS) öffnen, bearbeiten, speichern, und erzeugt keinen Overhead, der eh nicht notwendig wäre. Denn TStringGrids unterstützen doch eh nur Strings soweit ich weiß. Dann hättest du fast einen "Einzeiler", und null Probleme, selbst wenn Excel nicht installiert ist oder nicht gefunden wird (oder die API sich geänndert hat).
Delphi-Quellcode:
Das wäre zum Laden. Das Speichern ginge noch einfacher...
procedure LoadCSV(Lines: TStrings);
var Index: Integer; Cols: TArray<string>; I: Integer; begin StringGrid1.RowCount := Lines.Count; for Index := 0 to Lines.Count - 1 do begin Cols := Lines.Strings[index].Split([';', ','], '"', '"'); StringGrid1.ColCount := length(cols); for I := 0 to StringGrid1.ColCount - 1 do begin StringGrid1.Rows[index].Strings[I] := Cols[I]; end; end; end; |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Zitat:
Verschwinden leere Zellen? Gruß K-H |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
@Dennis07: Weil beim csv meines Wissens Formatierungen (also auch Farbvorgaben etc.) verloren gehen, die ich aber brauche. (Zu deiner Bemerkung mit den "strings": Das ist in Ordnung, ich möchte nur strings verwenden, selbst bei den Zahlen).
@K-H: Im Prinzip füllt er z.B. die erste Spalte nahezu komplett mit dem Wert aus der 2. Zeile. Wenn dort also "abc" steht, enthält nach dem speichern (beim einlesen ist dies noch korrekt) die erste Zeile in nahezu jeder Zeile "abc". Es hat ja schon mal funktioniert, daher wundere ich mich jetzt darüber. Ich rufe es übrigens ohne OpenDialog auf, sondern direkt, da hier keine Dialoge etc. stattfinden sollen. Aber daran kann es ja eigentlich nicht liegen oder? vorher (Eindeutige Zelleninhalte entfernt): ![]() nachher (Eindeutige Zelleninhalte entfernt): ![]() Es tauchen halt z.B. die Spaltenbeschriftungen innerhalb der Tabelle auch mehrfach auf, die Erste (und glaube zweite) Zeile ist auch noch korrekt, aber danach geht es halt los. Und alles was an Zahlen zu sehen ist, gehört halt eigentlich in die erste Spalte und zwar immer Zahl - 4 Felder frei - Zahl -... (in Excel sind hier 5 Zellen verbunden, das hat aber zwischenzeitlich einwandfrei funktioniert, stört also nicht). Aber den Zahlen fehlt hier die führende 0 (Die Zahlen müssen immer 4-Stellig sein, also theoretisch 0001 - 9999). |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Hmm...
Zitat:
Zitat:
Hast Du dein XLS-Dokument mit meinem Testtool geöffnet und gespeichert? Oder nur mit deinem Tool? 2.) Was Excel aus den übergebenen Daten macht, darauf hast Du nur dann Einfluss, wenn Du die Spalten/Cells/Ranges vor übergeben der Werte expliziert formatierst. Excel geht immer hin und 'versucht' die übergebenen Daten 'selber' zu interpretieren. Und da können auch Formatierungen verloren gehen. Gerade bei Strings mit Zahlen, denn eine '0001' ist als Zahl nunmal '1'. Wenn Du die führenden 000 haben willst, dann muss Du das Feld explizit als Text definieren. 3.) Haben deine Eingaben im Stringgrid vielleicht Tabs oder #0? Dann könnte dies Excel fehlinterpretieren und Spalten verschieben. 4.) Geh mal hin und formatiere deine Strings aus dem Grid mal (zum Testen) zu AnsiString, wenn Du sie in die Range packst. |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Das könnte daran liegen, dass das Stringrid 0-basiert und Excel 1-basiert seine Zeilen und Spalten zählt. Betrifft dann diesen Bereich:
Delphi-Quellcode:
Desweiteren kann es hier ggf. Sinn machen, für den Excel-Teil Used Range zu benutzen:
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; Result := True; MaxCol := Min(StringGrid.ColCount, XLApp.Workbooks[ExtractFileName(ExcelE.Text)].WorkSheets[sheetname].UsedRange.Columns.Count); MaxRow analog. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:53 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 by Thomas Breitkreuz