Autor Beitrag
hRb
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 267
Erhaltene Danke: 12



BeitragVerfasst: Fr 11.11.22 21:43 
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:
ausblenden 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.Add(StringGrid1.Rows[iRow].Delimitedtext := '|');
    sl.SaveToFile(fileName);
  finally
     sl.Free;
  end;
end;

Ich habe verschiedene schreibweisen probiert. Immer meckert der Compiler. Wie schreibt man folgende Zeile richtig?
ausblenden Delphi-Quelltext
1:
2:
3:
sl.Add(StringGrid1.Rows[iRow].Delimitedtext := '|');
sl.Add(StringGrid1.Rows[iRow].Delimitedtext['|']);
sl.Add(StringGrid1.Rows[iRow].Delimitedtext = '|');
ub60
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 762
Erhaltene Danke: 127



BeitragVerfasst: Fr 11.11.22 23:00 
Vielleicht einfach selber schreiben (ohne DelimitedText):

ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 267
Erhaltene Danke: 12



BeitragVerfasst: 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
ausblenden 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:
ausblenden 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)
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Sa 12.11.22 09:08 
Hallo,

die Eigenschaft heißt Delimiter - lies dir auch die Beschreibung zu DelimitedText durch.
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 267
Erhaltene Danke: 12



BeitragVerfasst: So 13.11.22 01:33 
Danke, Th69
Diese Beschreibung habe ich auch vorab gelesen. Unter 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 finde ich folgendes Beispiel:
ausblenden Delphi-Quelltext
1:
MyStringList.QuoteChar := #0;					

bei mir also
ausblenden Delphi-Quelltext
1:
s1.QuoteChar:= '|';					

wird vom Compiler angenommen. Auch die Zeile
ausblenden Delphi-Quelltext
1:
sx.Add(StringGrid1.Rows[iRow].Delimitedtext;					

also hier nochmals
ausblenden 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 user profile iconTh69: URL-Titel hinzugefügt
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: So 13.11.22 07:48 
Du weißt doch wie man Eigenschaften setzt:
ausblenden Delphi-Quelltext
1:
MyStringList.Delimiter := '|';					

Bei dir also (vor dem Add):
ausblenden 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), d.h. dein ursprünglicher Code müßte einwandfrei (auch mit Kommas) funktionieren.
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mo 14.11.22 13:09 
Hey,
dank user profile iconTh69 seiner guten Vorarbeit sollte alles zusammen dann etwa so aussehen:
ausblenden 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.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 14.11.22 14:37 
Hallo Sinspin,

da hast du dich aber noch etwas vertan - es muß so aussehen:
ausblenden 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:
ausblenden 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 267
Erhaltene Danke: 12



BeitragVerfasst: 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:
ausblenden 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 user profile iconTh69: Delphi-Tags hinzugefügt
Einloggen, um Attachments anzusehen!
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 267
Erhaltene Danke: 12



BeitragVerfasst: Mo 14.11.22 15:27 
Oh, jetzt sehe ich gerade den Korrektureintrag von Th69. Werde es testen
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 14.11.22 16:33 
Hat es geklappt?

user profile iconhRb hat folgendes geschrieben Zum zitierten Posting springen:
... und dann doch

Da fehlt das Ende des Satzes...
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: Mo 14.11.22 18:18 
user profile iconTh69 hat folgendes geschrieben Zum zitierten Posting springen:
Hallo Sinspin,

da hast du dich aber noch etwas vertan - es muß so aussehen:
ausblenden 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:

user profile iconhRb hat folgendes geschrieben Zum zitierten Posting springen:
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.
ausblenden 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;

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
hRb Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 267
Erhaltene Danke: 12



BeitragVerfasst: Mo 14.11.22 18:37 
Sorry, musste Einkaufen. Da wurde wohl ein halbfertiger Text gesendet.
So, in dieser Form funktioniert es:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 267
Erhaltene Danke: 12



BeitragVerfasst: 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")
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: 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).