![]() |
Excel Stringgrid in (vorhandene) Excel abspeichern
Moin zusammen,
ich bin es mal wieder. Ich hatte mir folgende Routine aus dem Netz geholt und etwas überarbeitet. Ich meine auch das sie bereits funktioniert hat, jetzt ist das Programm allerdings etwas größer geworden und nun funktioniert es nicht mehr (Die Daten werden nicht in Excel übernommen). Hat jemand evtl. eine Idee, denn eigentlich dürfte zusätzlicher Programmcode bei lokalen Variablen ja keinen Einfluss haben. Wichtig hierbei: Die Exceldatei wird vorher eingelesen (funktioniert mittlerweile 1A) und in eben diese sollen die Daten zurück geschrieben werden beim drücken auf Speichern, da diese im Stringgrid editiert werden (teilweise automatisch).
Code:
//Excel abspeichern (aus Grid)
procedure TTools.SpeichernFClick(Sender: TObject); var buttonSelected : Integer; logf : textfile; begin // Show a custom dialog buttonSelected := messagedlg('Daten in Excel übetragen und Speichern?',mtCustom, [mbYes,mbCancel], 0); // Show the button type selected if buttonSelected = mrYes then begin //Grid in Excel & Status anzeigen HinweisF.Show; ExcelSheets.Pages[0].Show; StringgridToXLS(DE_XLS, 'DE', ExcelE.Text); HinweisF.Caption := 'DE gespeichert'; ExcelSheets.Pages[ExcelSheets.ActivePageIndex + 1].Show; //... StringgridToXLS(Listen_XLS, 'Filiallisten', ExcelE.Text); HinweisF.Caption := 'Filiallisten gespeichert'; ExcelSheets.Pages[ExcelSheets.ActivePageIndex + 1].Show; StringgridToXLS(CuR_XLS, 'C&R', ExcelE.Text); HinweisF.Caption := 'Alles gespeichert'; ExcelSheets.Pages[0].Show; Timer2.Enabled := true; //Log schreiben assignfile(logf, ExtractFilePath(ParamStr(0)) + '\Log.txt'); reset(logf); append(logf); writeln(logf,DateToStr(Now) + ' - ' + TimeToStr(Now) + ' - ' + split(GetCurrentUserName, '.', 0) + ' - ' + ExcelE.Text + ' - gespeichert'); closefile(logf); LogList.Items.Clear; LogList.Items.LoadFromFile(ExtractFilePath(ParamStr(0)) + 'Log.txt'); end; end; //Inhalt eines TStringGrid nach Excel exportieren function TTools.StringgridToXLS(StringGrid : TStringGrid; sheetname : String; AXLSFile : string) : Boolean; var Col : Integer; Data : OleVariant; XLApp : OleVariant; MaxCol : Integer; MaxRow : Integer; Range : OleVariant; Row : Integer; Workbook : OleVariant; Worksheet : OleVariant; Value : OleVariant; begin Result := False; //Verbindung zu Excel herstellen XLApp := CreateOleObject('Excel.Application'); try if not VarIsNull(XLApp) then begin //Workbook öffnen XLApp.Workbooks.Open(AXLSFile); XLApp.Visible := false; if not VarIsNull(Workbook) then begin //Maximalen Bereich bestimmen MaxCol := Min(StringGrid.ColCount, XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[sheetname].Columns.Count); MaxRow := Min(StringGrid.RowCount, XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[sheetname].Rows.Count); if (MaxRow > 0) and (MaxCol > 0) then begin //Worksheet auswählen Worksheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].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; XLApp.Quit; XLAPP := Unassigned; Value := UnAssigned; Data := UnAssigned; Range := UnAssigned; Workbook := UnAssigned; end; end; end; //Hilfsfunktionen function TTools.StringToVariant(const SourceString : string) : Variant; var FloatValue : Extended; begin if TryStrToFloat(SourceString, FloatValue) then //Result := FloatValue //außer Kraft gesetzt, da ich (aktuell) nur Strings brauche, auch bei Zahlenwerten wegen führender Null Result := SourceString else Result := SourceString; end; |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
if not VarIsNull(Workbook) then
Workbook ist mMn an der Stelle Null weil nicht zugewiesen. Weiter oben hätte es wohl heißen müssen: Workbook:=XLApp.Workbooks.Open(AXLSFile); statt nur XLApp.Workbooks.Open(AXLSFile); ------- In der Folge könnte man dann auch statt: Worksheet := XLApp.Workbooks[ExtractFileName(AXLSFile)].WorkSheets[sheetname] einfach schreiben: Workbook.WorkSheets[sheetname] |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Was mir fehlt, ist eine Speicherung der übergebenen Daten und falls ich es richtig vermute, warum öffnest Du die bereits vorhandene Excel-Datei ein weiteres Mal?
Gruß K-H |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
@Jumpy: Da hast du recht, sehe ich genauso. Das ist aber der Teil, den ich unangetastet gelassen hatte. Aber auch eine Definition dessen ändert leider nichts. (Ein showmessage als Kontrolle, beweist zumindest das er die korrekten Werte ausliest für maxcol und maxrow).
@K-H: Was meinst du mit erneut öffnen? Die Exceldatei wird in die Stringgrids eingelesen (je Sheet ein Stringgrid). Und diese wird dann im Programm bearbeitet (manuell oder automatisch) und soll danach gespeichert werden können (wozu die oben genannte Routine genutzt werden soll). Ich selber vermute, das er nicht die richtigen Daten zum speichern übergibt, kann aber aktuell den Denkfehler nicht finden. ... Problem gefunden: Er übernimmt die richtigen Daten ABER bei der Speicherabfrage nimmt er quasi "nicht speichern". Wie kann ich ihm sagen, das er die Änderungen speichern soll? |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
![]() |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Dein Hinweis @ Codezwerg hat mir nicht wirklich geholfen, da dort kein Bezug auf das speichern genommen wird.
Habe nun woanders folgenden Code gefunden:
Code:
Damit funktioniert es nun.
Workbook.saveas(AXLSFile, EmptyParam, EmptyParam, EmptyParam, EmptyParam, EmptyParam, False, EmptyParam, EmptyParam, GetUserDefaultLCID);
|
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
In StringgridToXLS machst du das Workbook auf, schreibst den Kram rein und machst es wieder zu wenn du XLApp.Quit aufrufst. Und du hast nirgendwo gespeichert.
Es hilft nicht in der Aufrufendene Prozedur zu speichern, dann ist schon alles wieder weg! Deine Ganze Logik ist irgendwo komisch. Du solltest in der Prozedur in die vom Einlesen noch geöffnete Excel-Datei schreiben und nicht jedes mal fürs reinschreiben die Datei wieder öffnen (die ja wahrscheinlich eh noch geöffnet ist). |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Zitat:
|
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
@K-H: Bin gerade dabei deinem Tipp zu folgen und Excel bzw. die Datei früh zu öffnen (Programmstart) um sie später nicht immer öffnen und schließen zu müssen. Für das Einlesen der Excel funktioniert dies zwar, aber nicht für das speichern. Entweder bekomme ich die Rückmeldung im laufenden Programm "Ungültige varianten Operation" oder er schmeißt ab dem 2. Tabellenblatt alles falsch in Excel.
Ich habe folgenden Werte global deklariert: XLApp -> Excel AXLSFile -> Exceldatei Workbook -> Arbeitsbuch Und ich musste wegen eines Namenskonflikts auf openxml gehen, dann funktioniert aber meine obige Lösung nicht mehr. Weiß jemand wie ich eine Datei, die mit Openxml geöffnet wurde speicher? |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Zeig doch mal etwas mehr Code. Vielleicht steht da jetzt noch was mit deiner alten Variante vermischt.
|
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. |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
@Holger: mit deinem Tool in meinem integriert.
Delphi-Quellcode:
@jumpy: Da ich die "extrahierte" Version von Holger nutze kommt die angesprochene Zeile so nicht mehr vor.
if StringGridToXLS(FXLApp, DE_XLS, 'DE') then SaveExcel(FXLApp) else CloseExcel(FXLApp);
//... ...ggf. mache ich es nachher testweise nochmal so, wie ich es ursprünglich gefunden hatte ( ![]() |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Mit folgendem Schnipsel, kann man aus einem Stringgrid in eine Excel-Tabelle schreiben:
Delphi-Quellcode:
(um den Spaltenfehler hab ich mich damals leider nicht mehr gekümmert)
if forcestring then begin
excel.activesheet.Cells.NumberFormat := '@'; end; for i:=0 to sg.rowcount-1 do begin for j:=0 to sg.colcount-1 do begin zelle:=sg.cells[j,i]; {---- Fehler 800A03EC bei mehr als 255 Spalten!} excel.activesheet.cells(i+1,j+1):=zelle; {cells1..x/1..y } end; end; Damit wird auch 007 übernommen. Gruß K-H |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Es scheint ein Problem der Exceldatei zu sein.
Und zwar durch folgendes ausgelöst: Exceldatei ("jungfräulich") mit den Daten gefüllt - ok Exceldatei 1mal eingelesen - ok Exceldatei 1mal gespeichert - ok (Eintragungen passen) Exceldatei 2. Mal einlesen - Fehler -> Namenskonflikt (_Filterdatabase) aus Exceldatei alle versteckten Namen entfernt mit folgendem Macro:
Code:
Exceldatei 3. Mal einlesen - ok (Eintragungen passen, keine Fehlermeldung mehr)
Sub EntferneNamen()
Dim i As Name For Each DefName In ActiveWorkbook.Names DefName.Delete Next DefName End Sub Exceldatei 2. Mal speichern - alles durcheinander Das Problem scheint also mit dem Namenskonflikt zu sein, denn wenn dieser nicht auftreten würde, bräuchte ich das Makro nicht auszuführen, welches scheinbar "zu viel" löscht und zu dem Fehler führt. -.- Aktuell scheint die Lösung zu sein, Excel direkt noch zu speichern:
Delphi-Quellcode:
function StringGridToXLS(AXLApp : OleVariant; AGrid : TStringGrid; Sheetname : string):Boolean;
const xlCellTypeLastCell = $0000000B; var Sheet: OLEVariant; MaxCol : Integer; MaxRow : Integer; Range : OleVariant; Data : OleVariant; Col : Integer; Row : Integer; R1,R2 : string; begin Result := False; try //Worksheet auswählen if (Sheetname <> '') and HaveSheet(AXLApp, Sheetname) then begin Sheet := AXLApp.WorkSheets[sheetname]; end else Sheet := AXLApp.WorkSheets[1]; Sheet.select; // Der vorhandenen Daten im Grid, nicht der möglichen in Excel... MaxCol := AGrid.ColCount; MaxRow := AGrid.RowCount; if (MaxRow > 0) and (MaxCol > 0) then begin //Bereich auswählen R1 := RefToCell(1, 1); R2 := RefToCell(MaxCol, MaxRow); Range := Sheet.Range[R1, R2]; 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 Data[Succ(Row), Succ(Col)] := AGrid.Cells[Col, Row]; end; end; //Daten dem Excelsheet übergeben Range.Value := Data; Range.Columns.AutoFit; Result := True; end; end; finally SaveExcel(AXLApp); Range := UnAssigned; Sheet := Unassigned; Data := Unassigned; end; end; |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
So, ich arbeite nun mit dem Programm und seit der letzten Änderung (zwischendurch das Speichern) trat kein Namenskonflikt und auch sonst kein Problem mehr mit Excel auf :)
Danke für eure Hilfe und Unterstützung ;) Evtl. hilft der Thread auch anderen weiter, es war ja doch ein recht spezielles Problem. |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
Hallo Moombas,
ich will mal grundsätzlich die Frage stellen, ob Dein Vorgehen Zielführend ist. Ich habe das so verstanden: 1. Excel-Datei wird in einem Stringgrid eingelesen 2. In dem Stringgrid werden einigen Daten verändert 3. Das Stringgrid mit den veränderten Daten wird zurück in die Excel-Datei geschrieben Da die Synchronisierung zwischen Deinen Programm und Excel zu Problemen führen kann, stelle ich mal 2 Alternativen vor. Was spricht dagegen, die Daten die verändert werden sollen direkt in Excel mit Hilfe Deines Programms zu ändern, ohne den Umweg über das Stringgrid. Die andere Möglichkeit ist, die Daten aus der Excel-Datei in einem Stringgrid einzulesen, die Daten im Stringgrid zu verändern und anschließend in einer XLS-Datei ohne Excel zu speichern. Bis bald Chemiker |
AW: Excel Stringgrid in (vorhandene) Excel abspeichern
@Chemiker:
Der Umweg über das Stringgrid ist kein Umweg :) Die Daten der Exceldatei sollen über das Stringgrid geändert werden können und zusätzlich werden diese teilweise automatisiert geändert. Und wie gesagt seit der letzten Änderung ist nur einmal ein Problem aufgetreten, welches aber wohl an einer anderen Stelle lag. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:43 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