Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi StrinGrid in einer Datei speichern und auch wieder öffnen (https://www.delphipraxis.net/4720-stringrid-einer-datei-speichern-und-auch-wieder-oeffnen.html)

dopeline 9. Mai 2003 16:46


StrinGrid in einer Datei speichern und auch wieder öffnen
 
Hallo!

Ich hab eine Tabelle(StringGrid) und will diese in einer Datei speichern (mit SaveDialog). mit dem OpenDialog soll die Datei wieder geöffnet werden können und der inhalt wieder in die tabelle geschrieben werden sollen.
Wie stelle ich das an?

Grüße, dopeline

Luckie 9. Mai 2003 16:49

Die Dialoge dienen nur dazu dir einen Dateinamen zu liefern. Nicht mehr und nicht weniger. Um das Speichern mußt du sich schon selber kümmern.

kein in zwei verschachtelten for-Schleifen die Zeilen und Spalten durch und schreib sie in eine Stringliste.

Jens Schumann 9. Mai 2003 16:58

Hallo,
hier sind ein paar function's mit denen Du das machen kannst.
Delphi-Quellcode:
function GetToken(aString:String; SepChar: Char;TokenNum: Integer):String;
var
   Token    : String;
   StrLen   : Integer;
   TNum     : Integer;
   TEnd     : Integer;
begin
 StrLen := Length(aString);
 TNum  := 1;
 TEnd  := StrLen;
 while ((TNum <= TokenNum) and (TEnd <> 0)) do
   begin
    TEnd := Pos(SepChar,aString);
    if TEnd <> 0 then
      begin
      Token := Copy(aString,1,Tend - 1);
      Delete(aString,1,TEnd);
      Inc(TNum);
      end // if TEnd <> 0 then
      else
        begin
        Token := aString;
        end; // else if TEnd <> 0 then
    end; // while ((TNum <= TokenNum) and (TEnd <> 0)) do
 If TNum >= TokenNum then
   begin
   Result := Token;
   end // If TNum >= TokenNum then
   else
     begin
     Result := '';
     end;// else If TNum >= TokenNum then
end;

function NumToken(aString:String; SepChar: Char):Integer;
var
   RChar    : Char;
   StrLen   : Integer;
   TNum     : Integer;
   TEnd     : Integer;
begin
  If SepChar = '#' then
    RChar := '*'
    else
      RChar := '#';
  StrLen := Length(aString);
  TNum  := 0;
  TEnd  := StrLen;
  while TEnd <> 0 do
    begin
    Inc(TNum);
    TEnd := Pos(SepChar,aString);
    if TEnd <> 0 then
      begin
      aString[TEnd] := RChar;
      end;
    end;
 Result := TNum;
end;

procedure DeleteRow(yourStringGrid: TStringGrid; ARow: Integer);
var i: Integer;
begin
  with yourStringGrid do
  begin
    for i := ARow to RowCount-2 do
      Rows[i].Assign(Rows[i+1]);
    RowCount := RowCount - 1
  end;
end;

procedure DeleteEmptyGridRows(Grid : TStringGrid);
var
  aCol,
  aRow    : Integer;
  CheckSum : Integer;
begin
  CheckSum:=Grid.ColCount;
  aRow:=0;
  CheckSum:=0;
  While aRow<=Grid.RowCount-1 do
    begin
    CheckSum:=0;
    For aCol:=0 to Grid.ColCount-1 do
      begin
      If Grid.Cells[aCol,aRow]<>'' then
        Inc(CheckSum);
      end;
    If CheckSum=0 then
      DeleteRow(Grid,aRow)
      else
        Inc(aRow);
    end;
end;

function SaveGridToFile(Grid : TStringGrid; Filename : String; SepChar : Char; DelEmptyRows : Boolean) : Boolean;
var
  Tmp  : TStringList;
  aCol,
  aRow : Integer;
  H    : String;
  aGrid : TStringGrid;
begin
  Result:=True;
  Tmp:=TStringList.Create;
  aGrid:=TStringGrid.Create(Nil);
  Try
    Try
      aGrid.ColCount:=Grid.ColCount;
      aGrid.RowCount:=Grid.RowCount;
      For aRow:=0 to Grid.RowCount-1 do
        aGrid.Rows[aRow].Assign(Grid.Rows[aRow]);
      If DelEmptyRows then
        DeleteEmptyGridRows(aGrid);
      For aRow:=0 to aGrid.RowCount-1 do
        begin
        H:='';
        For aCol:=0 to aGrid.ColCount-1 do
          H:=H+Grid.Cells[aCol,aRow]+SepChar;
        Tmp.Add(H);
        end;
      Tmp.SaveToFile(Filename);
    Except
      Result:=False;
    end;
  Finally
    aGrid.Free;
    Tmp.Free;
  end;
end;

function LoadGridFromFile(Grid : TStringGrid; Filename : String; SepChar : Char) : Boolean;
var
  Tmp         : TStringList;
  NewColCount : Integer;
  aCol,
  aRow        : Integer;
begin
  Result:=True;
  Tmp:=TStringList.Create;
  Try
    Try
      Tmp.LoadFromFile(Filename);
      NewColCount:=NumToken(Tmp.Strings[0],SepChar)-1;
      Grid.ColCount:=NewColCount;
      Grid.RowCount:=Tmp.Count;
      For aRow:=0 to Tmp.Count-1 do
        begin
        For aCol:=1 to NewColCount do
          Grid.Cells[aCol-1,aRow]:=GetToken(Tmp[aRow],SepChar,aCol);
        end;
    Except
      Result:=False;
    end;
  Finally
    Tmp.Free;
  end;
end;
Die Funktionen auf die es ankommt sind:
function SaveGridToFile(Grid : TStringGrid; Filename : String; SepChar : Char; DelEmptyRows : Boolean) : Boolean;
function LoadGridFromFile(Grid : TStringGrid; Filename : String; SepChar : Char) : Boolean;

Die proceduren DeleteEmptyGridRows, DeleteRow, GetToken und NumToken sind nur Hilfsproceduren

Parameter für SaveGridToFile:
Grid : Das TStringGrid, dessn Inhalt gespeichert werden soll
Filename : Pfad und Dateiname
SepChar : Das Separierungzeichen für die einzelnen Strings einer Zeile z.B. ein ;
DelEmptyRows : Wenn True, dann werden alle Zeilen ohne Inhalt nicht gespeichert.

Parameter LoadGridFromFile:
Grid : Das TStringGrid, dessn Inhalt gespeichert werden soll
Filename : Pfad und Dateiname
SepChar : Das Separierungzeichen für die einzelnen Strings einer Zeile z.B. ein ;

Keldorn 9. Mai 2003 19:08

Zitat:

Zitat von Jens Schumann
Hallo,
hier sind ein paar function's mit denen Du das machen kannst.

Hallo

sorry, finde ich zu kompliziert.
insbeondere das Seperierungszeichen brauchst du nicht. Row und Col sind Tstrings und die bringen mit commatext schon sowas von haus aus mit.

hier ist eine andere Variante:
http://www.tipps.delphi-source.de/ob...010805-6.shtml

Mfg Frank

Jens Schumann 9. Mai 2003 19:17

Hallo Keldorn,
Du hast recht im Vergleich mit
http://www.tipps.delphi-source.de/oberflaeche/tut20010805-6.shtml
ist es tatsächlich komplizierter.
Das mit dem SepChar hat natürlich seinen Grund. Damals, als meine Kunden noch Win 95 nutzen ist beim Zugriff von Delphi auf Excel der Rechner ständig abgeschmiert (Macke unter Win95 wenn man zu viele Interfacezeiger anfordert). Ich brauchte jedoch einen Export nach Excel. Da Excel von Haus aus den TapStop als SepChar eingestellt hat habe ich mir die o.g. Funktionen gebastelt. Damit brauchen die Anwender im Textdateiöffnungsassistenten (was für ein Wort) nur auf Fertigstellen klicken.

Keldorn 9. Mai 2003 19:17

außerdem sind fehler drin

Delphi-Quellcode:
      If DelEmptyRows then
        DeleteEmptyGridRows(aGrid);
      For aRow:=0 to aGrid.RowCount-1 do
        begin
        H:='';
        For aCol:=0 to aGrid.ColCount-1 do
          H:=H+Grid.Cells[aCol,aRow]+SepChar;
        Tmp.Add(H);
        end;
      Tmp.SaveToFile(Filename);
du löschst mit deleteemptyrows die leeren Zeilen, ok
anschließen durchläufst du die Zellen deines Hilfsgrids aGrid bis zum ende
holst dir die Strings aber vom Originalem Grid (Grid)
Zitat:

H:=H+Grid.Cells[aCol,aRow]+SepChar;
wenn du Zeilen gelöscht hast, wird dann abver irgendie was nicht stimmen ...

Mfg Frank

Jens Schumann 9. Mai 2003 19:21

Hallo Keldorn,
Du hast schon wieder recht.
Es muss natürlich
Delphi-Quellcode:
H:=H+aGrid.Cells[aCol,aRow]+SepChar;
lauten.

Vielen Dank für den Hinweis.
Der Fehler hat sich bei mir noch nie bermkbar gemacht.

Keldorn 9. Mai 2003 19:22

Zitat:

Zitat von Jens Schumann
Hallo Keldorn,

Das mit dem SepChar hat natürlich seinen Grund. Damals, als meine Kunden noch Win 95 nutzen ist beim Zugriff von Delphi auf Excel der Rechner ständig abgeschmiert (Macke unter Win95 wenn man zu viele Interfacezeiger anfordert). Ich brauchte jedoch einen Export nach Excel.

hab jetzt nur D3, da gehts noch nicht aber bei aktuelleren Delphi´s gibt wenn ich mich richtig erinnere es bei Tstrings noch mit DelimetedText (oder so ähnlich) noch die Möglichkeit, einen eigenen Seperator festzulegen. Gugg mal dort nach

Jens Schumann 9. Mai 2003 19:26

Hallo Keldorn,
die Möglichkeit des eigenen SepChar gibt es ab D6.
Ich verwende aber immer noch D5 (wegen vielen Bugs in D6).
Da aber meine Kunden jetzt alle min Win2000 verwenden und dort die
Automationschnittstelle zu Excel einwandfrei funktioniert benötige
ich die Funktionen SaveGridToFile und LoadGridFromFile gar nicht mehr.

dopeline 9. Mai 2003 19:29

Also diese variante funktioniert einwandfrei und ist außerdem übersichtlich. vielen dank!

Gruß, dopeline :dancer:

dopeline 10. Mai 2003 13:01

mit der löschmethode (DeleteRow) löscht man immer die unterste zeile der tabelle. wie stelle ich das so um, dass nur die zeile, die ich markiert habe gelöscht wird?

Grüße, dopeline :dancer:

Jens Schumann 10. Mai 2003 18:20

Hallo dopeline,
ich habe DeleteRow gerade getestet. Es wird genau die Zeile gelöscht, die im Paramter ARow übergeben wird.

dopeline 10. Mai 2003 18:52

:( :( :( also irgentwie will das nicht...

und da gibt es keine andere möglichkeit?! :?

dass er einließt, in welcher zeile er gerade ist und diese dann löscht.

ssach 11. Mai 2003 02:21

hy,

also saven kannstdu ein stringrid in eine csv datei so :

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
R, C : integeR;
S : string;
begin
   if SaveDialog.Execute then
   begin
   for R := 0 to sg.RowCount - 1 do
      begin
         S := '';
         for C := 0 to sg.ColCount - 1 do
            S := S + sg.Cells[C,R] + ';';
         delete(S,length(S),1);  //loescht den ueberfluessigen ;
         lb.Items.Append(S);
      end;

   lb.Items.SaveToFile('SaveDialog.Filename');
   end;
end;
die passende funtion zum laden hab ich gerade nicht bei hand aber schicke dir sie so schnel es geht!

cu

dopeline 11. Mai 2003 07:05

Also das mit dem Speichern klappt schon wunderbar! jetzt ist noch dolgendes problem:

ich will (im laufenden programm) eine zeile markieren und diese dann mit einem button/short-cut entfehrnen. ich hab mir schon einige sachen ageschaut, aber da wurde immer nur die letzte (unterste) zeile der tabelle entfernt. man müsste gucken, welche zeile gerade markiert ist und sie dann löschen. (vielleicht mit onSelectCell ?)

Gruß, dopeline

Sharky 11. Mai 2003 07:52

Habe kein DeleteRow im StringGrid?
 
hmmm... eigentlich sollte das mit

StringGrid.DeleteRow (Stringgrid.row);

gehen. Aber mein StringGrid hat die Methode DeleteRow nicht :?:

Kann mir einer sagen warum?

dopeline 11. Mai 2003 14:38

ich hab da noch ne frage:

wenn ich eine datei öffne bearbeite und dann wieder speichern will, erscheint immer der savedialog. beim abspeichern kommt dann die anfrage zum überschreiben (ist auch richtig so). das ist aber eher eine "Speichern unter"-Lösung. ich will, dass wenn ich ein dokument öffne, bearbeite und dann normal auf "speichern" (nicht auf "speichern unter") gehe, er das dokument am gleichen ort und mit dem gleich dateinamen abspeichert. (ohne den savedialog!).

da müsste doch in einer variablen gespeichert werden, von wo die datei geöffnet wurde und wie sie heißt ==> und bei "normalem" speichern müsste er den savedialog weglassen. als dateipfad und dateiname springt dann die variable ein...

geht das irgentwie so in der art? (oder auch anders)
wenn ja, wie?

Grüße, dopeline

Luckie 11. Mai 2003 15:45

Das geht genauso, wie du es beschrieben hast. Warum programmierst du es nicht einfach und kuckst, was passiert? :roll:

dopeline 11. Mai 2003 18:36

ok habs hinbekommen. ich hab gesagt er soll beim öffnen die daten einlesen:
Code:
datei:=opendialog1.filename;
und beim "normalen" speichern guckt er, ob in "date" etwas drin steht.
wenn ja:
Code:
SaveToFile(datei);
wenn nicht, kommt der saveialog.

funktioniert super!

dopeline 11. Mai 2003 18:41

wie mache ich es, wenn die datei erfolgreich (ohne savedialog) abgespeichert wurde, dass unten in der satusbar, für eine gewisse zeit, eine Meldung kommt (z.b."Das Dokument wurde erfolgreich gespeichert")?


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:35 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-2025 by Thomas Breitkreuz