Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - DelimitedText, richtige Schreibweise?
hRb - Fr 11.11.22 21:43
Titel: DelimitedText, richtige Schreibweise?
Ich will ein Stringgrid speichern, jedoch anstellle von Commatext das Trennzeichen '|' nutzen, da das Komma in den Daten selbst vorkommen kann. Meine Procedure mit Komma als Trennzeichen funktioniert und sieht wie folgt aus:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure SaveGrid(StringGrid1: TStringGrid; fileName: string); var iRow: integer; sl: TStringList; begin try sl := TStringList.Create; for iRow := 0 to StringGrid1.RowCount - 1 do sl.Add(StringGrid1.Rows[iRow].CommaText); sl.SaveToFile(fileName); finally sl.Free; end; end; |
Ich habe verschiedene schreibweisen probiert. Immer meckert der Compiler. Wie schreibt man folgende Zeile richtig?
Delphi-Quelltext
1: 2: 3:
| sl.Add(StringGrid1.Rows[iRow].Delimitedtext := '|'); sl.Add(StringGrid1.Rows[iRow].Delimitedtext['|']); sl.Add(StringGrid1.Rows[iRow].Delimitedtext = '|'); |
ub60 - Fr 11.11.22 23:00
Vielleicht einfach selber schreiben (ohne DelimitedText):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| procedure SaveGrid(StringGrid1: TStringGrid; fileName: string); var iRow, iCol: integer; sl: TStringList; s: String; begin try sl := TStringList.Create; for iRow := 0 to StringGrid1.RowCount - 1 do begin s:=StringGrid1.Cells[0, iRow]; for iCol := 1 to StringGrid1.ColCount - 1 do s:=s+'|'+StringGrid1.Cells[iCol, iRow]; sl.Add(s); end; sl.SaveToFile(fileName); finally sl.Free; end; end; |
ub60
hRb - Fr 11.11.22 23:57
Ja, das ist natürlich möglich. Aber man speichert nicht, wenn nicht auch wieder gelesen werden soll und da ist die "automatische Trennzeichen-Auswertung" schon elegant. Siehe unten
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure LoadFromFile(StringGrid1: TStringGrid; txt: TFileName); var sRows, sCols: TStrings; i: Integer; begin sRows := TStringList.Create; sRows.LoadFromFile(txt); sCols := TStringList.Create; sCols.CommaText := sRows[0]; StringGrid1.ColCount := sCols.Count; sCols.Free; StringGrid1.RowCount := sRows.Count; for i := 0 to Pred(sRows.Count) do StringGrid1.Rows[i].CommaText := sRows[i]; sRows.Free; end; |
also ganz einfach:
Delphi-Quelltext
1:
| StringGrid1.Rows[i].CommaText := sRows[i]; |
Deshalb auch hier die Frage: wie? (für mich als Nichtprofi auch zusätzlich ein Punkt zum weiteren Lernen)
hRb - So 13.11.22 01:33
Danke, Th69
Diese Beschreibung habe ich auch vorab gelesen. Unter
DelimitedText [
https://docwiki.embarcadero.com/Libraries/Alexandria/de/System.Classes.TStrings.DelimitedText] steht jedoch nur, dass
DelimitedText ein Wert zuzuweisen sei. Ein Beispiel fehlt!
Ich dachte, dass anstelle
CommaText, einfach die von mir auskommentierte Zeile zu schreiben wäre.
Unter
QuoteChar [
https://docwiki.embarcadero.com/Libraries/Alexandria/de/System.Classes.TStrings.QuoteChar] finde ich folgendes Beispiel:
Delphi-Quelltext
1:
| MyStringList.QuoteChar := #0; |
bei mir also
wird vom Compiler angenommen. Auch die Zeile
Delphi-Quelltext
1:
| sx.Add(StringGrid1.Rows[iRow].Delimitedtext; |
also hier nochmals
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure SaveGrid(StringGrid1: TStringGrid; fileName: string); var iRow: integer; sx: TStringList; begin try sx := TStringList.Create; sx.QuoteChar := '|'; for iRow := 0 to StringGrid1.RowCount - 1 do sx.Add(StringGrid1.Rows[iRow].Delimitedtext); sx.SaveToFile(fileName); finally sx.Free; end; end; |
Das Ergebnis beim Trennzeichen ist aber nach wie vor das Komma.
Die weiteren Seiten in der Hilfe zum Thema habe ich alle gelesen: jedoch ohne lauffähiges Beispiel. Hat mir alles nicht geholfen.
Daher nochmals nachgefragt: Wie ändere ich den Delimiter?
Moderiert von Th69: URL-Titel hinzugefügt
Th69 - So 13.11.22 07:48
Du weißt doch wie man Eigenschaften setzt:
Delphi-Quelltext
1:
| MyStringList.Delimiter := '|'; |
Bei dir also (vor dem
Add):
Delphi-Quelltext
1:
| StringGrid1.Rows[iRow].Delimiter := '|'; |
PS:
QuoteChar ist für das zusätzliche Setzen in Anführungszeichen (oder andere Zeichen), d.h. vor und nach jedem Eintrag. Dies wäre also eine andere Alternative, um Kommas in Texten abzuspeichern und wieder korrekt zu lesen (s.a.
CommaText [
https://docwiki.embarcadero.com/Libraries/Alexandria/de/System.Classes.TStrings.CommaText]), d.h. dein ursprünglicher Code müßte einwandfrei (auch mit Kommas) funktionieren.
Sinspin - Mo 14.11.22 13:09
Hey,
dank
Th69 seiner guten Vorarbeit sollte alles zusammen dann etwa so aussehen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure SaveGrid(StringGrid1: TStringGrid; fileName: string); var iRow: integer; sl: TStringList; begin try sl := TStringList.Create; for iRow := 0 to StringGrid1.RowCount - 1 do begin StringGrid1.Rows[iRow].DelimitedText := '|'; sl.Add(StringGrid1.Rows[iRow].CommaText); end; sl.SaveToFile(fileName); finally sl.Free; end; end; |
Dabei wird die TStringList "sl" gelassen wie eingestellt.
Vor dem Auslesen der Eigenschaft CommaText, der Zeile des TStringGrid müssen alle Eigenschaften gesetzt sein die CommaText verwendet um den formatierten String zu erzeugen.
Übrigens ist es keine gute Idee "#0" an irgend einer Stelle als Stringtrenner zu verwenden. Das kann(wird) zu lustigen Fehlern führen wenn man sein Programm mal aus der Delphiwelt heraus lässt.
Th69 - Mo 14.11.22 14:37
Hallo Sinspin,
da hast du dich aber noch etwas vertan - es muß so aussehen:
Delphi-Quelltext
1: 2:
| StringGrid1.Rows[iRow].Delimiter := '|'; sl.Add(StringGrid1.Rows[iRow].DelimitedText); |
;-)
PS: Bzw. persönlich würde ich es (laufzeit-optimiert) so schreiben:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| var rowStrings: TStrings; begin {$ ... $}
rowStrings := StringGrid1.Rows[iRow]; rowStrings.Delimiter := '|'; sl.Add(rowStrings.DelimitedText);
{$ ... $} end |
hRb - Mo 14.11.22 15:25
Also so wie im Beispiel angegeben funktioniert es nicht.
(Habe zunächst Schleifenvariable korrigiert in
for j:=cFixRow = 1 to .., da eine Überschriftenzeile. Aber das nur nebenbei)
Meine Stringliste sah vor dem Speichern wie folgt aus (s. Image 4)
Nach der Procedure waren alle Einträge aus meiner Stringliste gelöscht und in Spalte 1 war überall | (s.Image5)
In der Textdatei in die ich die Liste speichere sieht es ähnlich aus:
Quelltext
1: 2: 3: 4: 5: 6:
| |,,,,,,,, |,,,,,,,, |,,,,,,,, |,,,,,,,, |,,,,,,,, |,,,,,,,, |
Anmerkung: Habe mich auch gewundert, dass
StringGrid1.Rows[iRow].DelimitedText := '|'; innerhalb der Schleife und vor jedem Add steht und dann doch
Moderiert von Th69: Delphi-Tags hinzugefügt
hRb - Mo 14.11.22 15:27
Oh, jetzt sehe ich gerade den Korrektureintrag von Th69. Werde es testen
Th69 - Mo 14.11.22 16:33
Hat es geklappt?
hRb hat folgendes geschrieben : |
... und dann doch |
Da fehlt das Ende des Satzes...
Sinspin - Mo 14.11.22 18:18
Th69 hat folgendes geschrieben : |
Hallo Sinspin,
da hast du dich aber noch etwas vertan - es muß so aussehen:
Delphi-Quelltext 1: 2:
| StringGrid1.Rows[iRow].Delimiter := '|'; sl.Add(StringGrid1.Rows[iRow].DelimitedText); |
;-) |
...und wie Du recht hast.
Wenn man versucht mal was so nebenbei zu machen. :oops:
hRb hat folgendes geschrieben : |
Anmerkung: Habe mich auch gewundert, dass StringGrid1.Rows[iRow].DelimitedText := '|'; innerhalb der Schleife und vor jedem Add steht |
Jede Row ist ja eine extra TStringList, von der niemand weis ob "Delimiter" richtig steht. "DelimitedText" zu überschreiben ist hingegen Blödsinn da es den Inhalt des StringGrids killt.
Ich versuche es nochmal, und jetzt richtig. Hoffentlich.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| procedure SaveGrid(StringGrid1: TStringGrid; fileName: string); var iRow: integer; sl: TStringList; begin try sl := TStringList.Create; for iRow := 0 to StringGrid1.RowCount - 1 do begin StringGrid1.Rows[iRow].Delimiter := '|'; sl.Add(StringGrid1.Rows[iRow].DelimitedText); end; sl.SaveToFile(fileName); finally sl.Free; end; end; |
hRb - Mo 14.11.22 18:37
Sorry, musste Einkaufen. Da wurde wohl ein halbfertiger Text gesendet.
So, in dieser Form funktioniert es:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| procedure SaveGrid(StringGrid1: TStringGrid; fileName: string); var iRow: integer; rowStrings : TStringList; begin try rowStrings := TStringList.Create; for iRow := 1 to StringGrid1.RowCount - 1 do begin StringGrid1.Rows[iRow].Delimiter := '|'; rowStrings.Add(StringGrid1.Rows[iRow].DelimitedText); end; rowStrings.SaveToFile(fileName); finally rowStrings.Free; end; end;
procedure TForm1.BilderlisteSpeichern1Click(Sender: TObject); VAR Dateiname:string; begin if FileSaveDialog1.Execute then begin Dateiname := FileSaveDialog1.FileName; SaveGrid(Stringgrid1,Dateiname); end; end; |
Anmerkung1: Die optimierte Version
rowStrings := StringGrid1.Rows[iRow] ; mag der Compiler nicht (Semikolon ist rot unterstrichen)
Anmerkung2:
Zitat: |
Übrigens ist es keine gute Idee "#0" an irgend einer Stelle als Stringtrenner zu verwenden. |
Da stimme ich zu, aber ich habe den Befehl einfach aus den Beispielen von Embarcadero übernommen.
Danke, Ihr seid schneller als ich. Dafür ist mein Kühlschrank wieder voll :D
Th69 - Mo 14.11.22 18:50
Das würde mich jetzt aber doch interessieren, warum mein anderer Code nicht funktioniert (denn denselben Code mehrfach zu wiederholen, sollte man ja vermeiden). Welche genaue Fehlermeldung gibt es denn beim Kompilieren?
Edit: Sehe jetzt gerade, daß du ja jetzt sl nicht mehr benutzt, sondern stattdessen rowStrings - du brauchst schon 2 verschiedene Variablen dafür.
hRb - Di 15.11.22 00:40
Die Fehlermeldung lautet: Inkompatible Typen: TStringlist und TStrings
Zitat: |
Sehe jetzt gerade, daß du ja jetzt sl nicht mehr benutzt, sondern stattdessen rowStrings - du brauchst schon 2 verschiedene Variablen dafür. |
Die Variable s1 (1=Zahl) wollte ich künftig nicht mehr nutzen. Im Delphi-Editor gibt es leicht Verwechslung mit sl (1=Zahl) und sl (= kleiner Buchstabe L)
2 verschiedene Variablen? Ok, wenn dies optimiert ist!
Läuft jetzt auch so (schwere Geburt, Danke fürs "Mitpressen")
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| procedure SaveGrid(StringGrid1: TStringGrid; fileName: string); var iRow: integer; rowStrings : TStrings; sL:Tstringlist; begin try sL := TStringList.Create; for iRow := 1 to StringGrid1.RowCount - 1 do begin rowStrings := StringGrid1.Rows[iRow]; rowStrings.Delimiter := '|'; sL.Add(rowStrings.DelimitedText); end; sL.SaveToFile(fileName); finally sL.Free; end; end; |
Th69 - Di 15.11.22 09:46
Optimiert in dem Sinne, daß nur einmal (pro Schleifendurchgang) auf das Rows-Array zugegriffen wird (die zusätzliche lokale Variable wird Delphi wohl im Release-Modus als Register benutzen, d.h. keine Stackvariable dafür anlegen) - dies ist zwar laufzeittechnisch nur eine Mikrooptimierung, ich finde den Code aber so schöner zu lesen, so daß je Objekt nur ein Zugriff darauf passiert (bei einer Funktion würde man diese ja auch nicht mehrfach aufrufen).
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2024 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!