Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi StringGrid Zeile per Mausclick auslesen (https://www.delphipraxis.net/121427-stringgrid-zeile-per-mausclick-auslesen.html)

klausmaus 27. Sep 2008 09:56


StringGrid Zeile per Mausclick auslesen
 
Hallo Leute,

bin ein Newbie und habe folg. Problem:
Über Editfelder werden Daten in ein StringGrid eingelesen, gespeichert und sortiert. Habe auch `ne Suche, die gewünschte Datensätze in den Editfeldern ausgibt.
Möchte nun zusätzlich, dass beim anklicken einer Zeile die Editfelder mit den entsprechenden Daten gefüllt werden. Wie krieg ich das hin? (Options.goRowSelect ist true)

Klaus01 27. Sep 2008 10:57

Re: StringGrid Zeile per Mausclick auslesen
 
Hallo,

du könntest mit dem Event/Ereignis OnSelectCell arbeiten:

Delphi-Quellcode:
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
begin

end;
Dort wird dir die markierte Zeile und Spalte übergeben.

Grüße
Klaus

klausmaus 27. Sep 2008 11:12

Re: StringGrid Zeile per Mausclick auslesen
 
Danke für den Tipp,

komme heute leider nicht mehr dazu, es auszuprobieren. Melde mich morgen wieder mit dem Ergebnis.

Schönes WE

klausmaus 28. Sep 2008 15:20

Re: StringGrid Zeile per Mausclick auslesen
 
Nach reichlich Bastelei bin jetzt soweit, das was ausgegeben wird.
Aber: wg. zeile
Delphi-Quellcode:
ARow:=Filepos(ChemDat)+1;
wird immer der erste Datensatz ausgegeben.
Wie krieg ich den aktuellen (angeklickten) Datensatz?
Hier der Code
Delphi-Quellcode:
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
  var CanSelect: Boolean);
  begin
  If CanSelect=True then
    seek(ChemDat,0);
      with Chem do
        ARow:=Filepos(ChemDat)+1;
        begin
          read(ChemDat,Chem);
          EditNr.Text:=(StringGrid1.Cells[1,ARow]);
          EditName.Text:=StringGrid1.Cells[2,ARow];
          DateTimePicker1.Date:=StrToDate(StringGrid1.Cells[4,ARow]);
        end;
  end;
Wäre prima, wenn jemand `nen Tipp hätte.

DeddyH 28. Sep 2008 15:22

Re: StringGrid Zeile per Mausclick auslesen
 
Zitat:

Delphi-Quellcode:
ARow:=Filepos(ChemDat)+1;

Du willst ARow setzen statt es auszuwerten?

klausmaus 28. Sep 2008 15:35

Re: StringGrid Zeile per Mausclick auslesen
 
Oh Mann was bin ich doof.
Zeile entfernt und schon klappt es.

Besten Dank

BTW
Möchte den in den Edit-Feldern angezeigten Datensatz im StringGrid löschen. Wie stelle ich das an?

DeddyH 28. Sep 2008 15:41

Re: StringGrid Zeile per Mausclick auslesen
 
Spontan würde ich sagen:
- StringGrid zeilenweise durchlaufen und Inhalte vergleichen
- wenn gefunden, dann nachfolgende Zeilen aufrücken lassen
und RowCount neu setzen

klausmaus 28. Sep 2008 15:48

Re: StringGrid Zeile per Mausclick auslesen
 
Ein Datenvergleich ist m.E. nicht nötig. Habe die Daten im Edit. Demzufolge müsste der Zeiger doch auf diesen bzw. den nächsten Datensatz zeigen.
Ergo: Filepos irgendwie auswerten und anschließend RowCount um 1 zuurücksetzen und dann das Grid neu einlesen.
Soweit meine Idee.
Aber mit der Umsetzung haperts.

DeddyH 28. Sep 2008 15:55

Re: StringGrid Zeile per Mausclick auslesen
 
Nochmal zum Verständnis: wenn Du eine Zelle im StringGrid anklickst, werden dessen Daten in den Edits angezeigt?

klausmaus 28. Sep 2008 16:04

Re: StringGrid Zeile per Mausclick auslesen
 
Habs nochmal gecheckt. Egal, welche Zelle ich anklicke, der entsprechende Datensatz wird in den Edits gezeigt.

DeddyH 28. Sep 2008 16:07

Re: StringGrid Zeile per Mausclick auslesen
 
Und das soll ja so sein, oder? Nun soll diese entsprechende Zeile gelöscht werden?

klausmaus 28. Sep 2008 16:13

Re: StringGrid Zeile per Mausclick auslesen
 
korrekt.
Zur Info: Soll als Beleg zum Thema Dateiarbeit ein Proggi schreiben.
Da ich Chemielehrer bin, versuch ich eine Chemikalienverwaltung (Zu- und Abgänge; Bestand). Da es ja mal passieren kann, dass eine Chemikale nicht mehr verwendet wird oder Fehleingaben passieren, soll dieser Datensatz gelöscht werden können.

DeddyH 28. Sep 2008 16:17

Re: StringGrid Zeile per Mausclick auslesen
 
Dann versuch es mal ganz simpel mit
Delphi-Quellcode:
StringGrid.Rows.Delete(StringGrid.Row);
Sollte eigentlich so funktionieren, hab ich aber nicht ausprobiert, ich mache zu wenig mit StringGrid.

klausmaus 28. Sep 2008 16:23

Re: StringGrid Zeile per Mausclick auslesen
 
Danke für den Tipp.
Melde mich Dienstag abend mit dem Ergebnis.

Schönen Sonntag noch.

toms 28. Sep 2008 16:27

Re: StringGrid Zeile per Mausclick auslesen
 
Zitat:

Zitat von DeddyH
Dann versuch es mal ganz simpel mit
Delphi-Quellcode:
StringGrid.Rows.Delete(StringGrid.Row);
Sollte eigentlich so funktionieren, hab ich aber nicht ausprobiert, ich mache zu wenig mit StringGrid.

Funktioniert nicht.

Delphi-Quellcode:
type
  TMyStringGrid = class(TStringGrid);

procedure TForm1.Button1Click(Sender: TObject);
begin
  TMyStringGrid(StringGrid1).DeleteRow(ZeilenIndex);
end;

DeddyH 28. Sep 2008 16:38

Re: StringGrid Zeile per Mausclick auslesen
 
Dann eben so ;)

klausmaus 1. Okt 2008 13:47

Re: StringGrid Zeile per Mausclick auslesen
 
Hat etwas länger gedauert.
Zunächst mal danke für die Tipps. Als ich am Basteln war stellte ich fest:
Fehler in der Denke!
Ich mache Folgendes:
-Edits auslesen
-Datensätze in Datei schreiben
-anschließend wieder auslesen und im StringGrid ausgeben
Ergo: Durch Löschen im StringGrid ändert sich ja nichts am Dateiinhalt. Da ich nicht alles ummodeln wollte bin ich auf folg. Prozedur gekommen:
Delphi-Quellcode:
procedure TForm1.DatenLoeschenClick(Sender: TObject);
  var i:SmallInt;
  begin
  seek(ChemDat,0);
  Assignfile(ChemDatH,'Hilf');
  rewrite(ChemDatH);
  for i:=0 to Stelle-1 do
    begin
     read(ChemDat,Chem) ;
     write(ChemDatH,Chem);
     end;
     seek(ChemDat,Stelle+1);
    while not eof (Chemdat) do
    begin
    read(ChemDat,Chem);
    write(ChemDatH,Chem);
    end;
    // bis hierhin klappts
    seek(ChemDat,0) ;
    seek(ChemDatH,0);
    begin
    read(ChemDatH,Chem);
    write(ChemDat,Chem);
    closefile(ChemDatH);
    end;

  end;
Funktioniert auch fast. Datensatz wird gelöscht. In der "Hilfsdatei" ChemDatH fehlt dann der gelöschte Datensatz.
Mit der den letzten Read/Write-Befehlen will ich die aktualisierten Daten wieder in die Ursprungsdatei schreiben. Das tuts aber nicht. Weshalb?
2.Frage: Wie krieg ich die "Hilfsdatei" wieder gelöscht?
3.Frage: Mir scheint das Hin-und Herschreiben etwas umständlich zu sein. Gibts eine elegante Variante?

taaktaak 1. Okt 2008 14:21

Re: StringGrid Zeile per Mausclick auslesen
 
Moin, Moin.
Nun, vielleicht nicht 2x kopieren, sondern die Originaldatei nach dem ersten Kopieren löschen und die Hilfsdatei umbenennen. Also DeleteFile() und RenameFile() verwenden.

// edit: Buchstabendreher, da muss man bei einem Lehrer ja aufpassen :shock:

klausmaus 1. Okt 2008 14:32

Re: StringGrid Zeile per Mausclick auslesen
 
Muss nachfragen: Du meinst folgendes:
-ChemDat (hat alte Daten) CloseFile und dann DeleteFile
anschließend
-ChemDatH (hat neue Daten) Closefile und dann Rename und dann Assignfile (brauch sie ja wieder geöffnet)?

//bin kein Krümelkacker :lol:

taaktaak 1. Okt 2008 14:33

Re: StringGrid Zeile per Mausclick auslesen
 
Jooo :thumb:

klausmaus 1. Okt 2008 14:39

Re: StringGrid Zeile per Mausclick auslesen
 
Probiers gleich mal aus.
Wäre prima, wenn du mir die Syntax für RenameFile verraten könntest.

Sag schon mal Danke :)

taaktaak 1. Okt 2008 14:43

Re: StringGrid Zeile per Mausclick auslesen
 
Delphi-Quellcode:
function RenameFile(const OldName,NewName:String):Boolean;
Einfach "RenameFile" eintippen, Caret drauf setzen und F1 drücken, dann zeigt die Hilfe (meist) was du wissen möchtest.

klausmaus 1. Okt 2008 15:12

Re: StringGrid Zeile per Mausclick auslesen
 
Bin wie gesagt ein absoluter Newbie (bis vor `nem halben Jahr lag Delphi in Griechenland) und auch nicht mehr der Jüngste. Mache das Ganze Nebenbei. Deshalb bleibts nicht aus, dass ich mich dusselig anstelle. Bin auf folg. Probleme gestoßen:
-habe Dateiname folgendermaßen deklariert
Delphi-Quellcode:
Dateiname:=Opendialog1.FileName;
      If Dateiname<>'' then
        begin
          AssignFile(ChemDat,Dateiname+'.dat');
          rewrite(chemdat);
        end;
Dann müsste
Delphi-Quellcode:
DeleteFile(Dateiname+'.dat');
korrekt sein

-Hilfsdatei wurde über
Delphi-Quellcode:
Assignfile(ChemDatH,'Hilf');
erstellt
Ergo müsste
Delphi-Quellcode:
RenameFile('Hilf',Dateiname+'.dat');
die Umbenennung erledigen

-vor dem Delete hab ich beide Dateien per CloseFile geschlossen

-Nun noch
Delphi-Quellcode:
AssignFile(ChemDat,Dateiname+'.dat');
Und es sollte gehen. Tuts aber leider nicht.

edit: Merke gerade: Kann ja gar nicht gehen. Woher soll er den neuen Namen kennen? Oder liege ich da falsch?

taaktaak 1. Okt 2008 15:45

Re: StringGrid Zeile per Mausclick auslesen
 
Tja, das könnte an (unterschiedlichen) Pfadangaben liegen. TOpenDialog gibt einen Dateiname inklusive eines Pfades zurück. Diese Information verwendest du für "Dateiname". Den Namen der Hilfsdatei erstellst du direkt im Programmcode - aber ohne eine Pfadangabe. Dadurch wird die Hilfsdatei im gerade aktuellen Verzeichnis angelegt. In diesem Verzeichnis wird die Hilfsdatei dann auch umbenannt. Das könnte das gleiche Verzeichnis sein, wird's aber wohl nicht. Die erneute Verwendung von "Dateiname" greift dann ins Leere, da sich die umbenannte (ehemalige) Hilfsdatei ganz woanders befindet.

So, das ist jetzt natürlich Spekulation. Um besser Helfen zu können, musst du konkreter berichten, was nicht funktioniert.

klausmaus 1. Okt 2008 16:19

Re: StringGrid Zeile per Mausclick auslesen
 
Die Hilf-Datei liegt im selben Pfad wie die eigentliche Datei. Ich poste hier nochmal die komplette Prozedur. Vermutlich hab ich einen Syntaxfehler gemacht, den der Debugger nicht zeigt.
Delphi-Quellcode:
procedure TForm1.DatenLoeschenClick(Sender: TObject);
  var i:SmallInt;

  begin
  seek(ChemDat,0);
  Assignfile(ChemDatH,'Hilf');
  rewrite(ChemDatH);

  for i:=0 to Stelle-1 do
    begin
     read(ChemDat,Chem) ;
     write(ChemDatH,Chem);
     end;
     seek(ChemDat,Stelle+1);

    while not eof (Chemdat) do
    begin
    read(ChemDat,Chem);
    write(ChemDatH,Chem);
    end;
// bis hierhin klappts
    CloseFile(ChemDat) ;
    CloseFile(ChemDatH) ;
    DeleteFile(Dateiname+'.dat');
    RenameFile('Hilf',Dateiname+'.dat');
    AssignFile(ChemDat,Dateiname+'.dat');
end;
Das Programm wird in einem anderen Verzeichnis gestartet. Die Dateien werden z.Zt. direkt auf Laufwerk D abgelegt. Dort finde ich sowohl die angelegte Datei als auch die Hilf-Datei.

Allerdings muss ich mich jetzt verabschieden. Mein Kind braucht einen Chauffeur.
Werd mal drüber schlafen. Melde mich morgen wieder.

Vielen Dank für deine bisherige Hilfe.

taaktaak 1. Okt 2008 17:59

Re: StringGrid Zeile per Mausclick auslesen
 
Zitat:

Dort finde ich sowohl die angelegte Datei als auch die Hilf-Datei.
Ok - das bedeutet wohl, dass weder DeleteFile() noch RenameFile() erfolgreich sind. In deiner Prozedur kann ich allerdings nichts finden, was Ursache für dieses Funktionsversagen sein könnte. Vielleicht hilft ein "Application.ProcessMessages" hinter dem 2ten CloseFile()? Ausprobieren...

Anmerkung:
Du arbeitest offenbar gern mit globalen Variablen, z.B. Chem, ChemDat, ChemDatH - ist vielleicht am Anfang recht bequem. Man sollte es aber tunlichst vermeiden (und sich gar nicht erst angewöhnen)! Wird das Programm umfangreicher sind das die "besten" Fehlerquellen.
Auch gehört zum "rewrite()" eine Fehlerbehandlung, schau' mal in die DelphiHilfe unter dem Stichwort "IOResult".

klausmaus 5. Okt 2008 15:35

Re: StringGrid Zeile per Mausclick auslesen
 
@taaktaak

Sorry, hat ein bisschen länger gedauert.
Dein Hinweis zur Globalisierung hat insofern geholfen, dass ich einen anderen Fehler beseitigen konnte.
Da du den Quelltext für Fehlerfrei erachtet hast, bin ich nochmal alles durchgegangen und siehe da, der Fehler lag woanders.
Beim Löschen schließe ich die Datei. Der nachfolgende Aufruf im Programm erwartet aber eine geöffnete Datei.

Da ich Probleme mit dem Umbenennen hatte bin ich wieder zur ursprünglichen Variante zurückgekehrt. Funktioniert theoretisch. Folgendes Problem:
-Reihenfolge der eingegebenen Datensätze: zeile1 / zeile2 / losch/ zeile3 / zeile4
-nach Aufruf der Löschprozedur für Datensatz losch lautet die Reihenfolge: zeile2 / zeile2 / losch/ zeile3 / zeile4
-in der Hilf-Datei steht die Reihenfolge: zeile2 / losch/ zeile3 / zeile4

Schlußfolgerung: In der ChemDat wurde statt des 3.Datensatzes der 1. gelöscht und der 2. Datensatz als 1. eingetragen.

Vielleicht kannst du rausfinden wo es da hakt.
Hier zunächst die Prozedur für die verwendete Suchfunktion:
Delphi-Quellcode:
procedure suchNam(Name:string; var ex:boolean; var Position:SmallInt);
  //Chemikaliensuche nach Namen
  begin
    seek(ChemDat,0);
    while not Eof(ChemDat) do
      begin
        read(ChemDat,Chem);
        If Name=Chem.Name then begin
                                ex:=true;
                                Position:=Filepos(ChemDat)-1;
                               end;
      end;
  end;
Folg. Quellcode soll löschen (Hab mal kommentiert, was ich damit erreichen will):
Delphi-Quellcode:
procedure TForm1.DatenLoeschenClick(Sender: TObject);
  var such:string; exist:boolean; Stelle:SmallInt; i:SmallInt;
                   z,s:Integer;
                   ChemDatH: TChemDat;
  begin
  Stelle:=0;
  seek(ChemDat,0);
  Assignfile(ChemDatH,'Hilf');
  rewrite(ChemDatH);
  such:=EditName.Text;
  suchNam(Chem.Name, exist, Stelle); //Aufruf Suchprozedur (s.o.)
    If exist then
     for i:=0 to Stelle-1 do
      begin
      seek(ChemDat,0);
      read(ChemDat,Chem) ; //Bis zur gesuchten Stelle (Name aus Edits)
      write(ChemDatH,Chem); //Bis dahin gelesenes in die Hilfsdatei schreiben
      end;
     seek(ChemDat,Stelle+1); // zu löschenden Datensatz überspringen
      while not eof (Chemdat) do
      begin
      read(ChemDat,Chem); //Rest lesen und schreiben
      write(ChemDatH,Chem);
      end;
   seek(ChemDatH,0);
   read(ChemdatH,Chem); // HilfsDatei auslesen
   seek(ChemDat,0);
   write(ChemDat,Chem); //ChemDat neu schreiben
   CloseFile(ChemDatH);
   //Erase(ChemDatH);
   seek(ChemDat,0);
    for i:=0 to FileSize(ChemDat)-1 do
      begin
        StringGrid1.Cells[0,i]:=IntToStr(FilePos(ChemDat));
        read(ChemDat,Chem);
        with Chem do                         //komplette ChemDat lesen und im StringGrid ausgeben
          begin
            StringGrid1.Cells[1,i+1]:=IntToStr(Chem.BNum);
            StringGrid1.Cells[2,i+1]:=Chem.Name;
            StringGrid1.Cells[3,i+1]:=IntToStr(Chem.Bestand);
            StringGrid1.Cells[4,i+1]:=Chem.Datum;
          end;
Die Hilfsdatei habe ich nach deinem Tipp lokal definiert. Die ChemDat muss m.E. global bleiben, da viele Prozeduren darauf zugreifen.

Gruß Michael

taaktaak 5. Okt 2008 18:20

Re: StringGrid Zeile per Mausclick auslesen
 
Moin, Moin Michael.

Zur Suchfunktion: Du hast eine Prozedur daraus gemacht. Typischerweise würde das tatsächlich eine Funktion sein, die als Ergebnis die gefundene Position zurückgibt. Wird der Datensatz nicht gefunden, wäre das Ergebnis -1 (da der erste Datensatz die Position 0 hat). Die Lösch-Prozedur ist zumindest an dieser Stelle falsch:

Delphi-Quellcode:
for i:=0 to Stelle-1 do begin
  seek(ChemDat,0);
  read(ChemDat,Chem) ;
  write(ChemDatH,Chem);
  end;
Da in jedem Schleifendurchlauf seek() aufgerufen wird, bewegst du dich nicht durch die Datei, sondern bleibst immer an der ersten Position. Das Auslesen der Hilfsdatei und (Neu)Schreiben von ChemDat ist falsch, da nur der erste Datensatz gelesen und geschrieben wird.

Vorschlag für neue Variante:

Delphi-Quellcode:
procedure TForm1.DatenLoeschenClick(Sender:TObject);
var DelPos : Integer;

  function NamePos(Name:String):Integer;
  begin
    Result:=-1;

    assignfile(ChemDat,Dateiname+'.dat');
    reset(ChemDat);

    while not Eof(ChemDat) do begin
      read(ChemDat,Chem);
      if Chem.Name=Name then begin
        Result:=FilePos(ChemDat);
        Break                        
        end
      end;

    closefile(ChemDat)
  end;

  procedure DeleteRecord(DelIdx:Integer);
  var RecIdx : Integer;
  begin
    assignfile(ChemDat,Dateiname+'.dat');
    reset(ChemDat);

    assignfile(ChemDatH,'Hilf');
    rewrite(ChemDatH);

    RecIdx:=-1;
    while not Eof(ChemDat) do begin
      read(ChemDat,Chem);
      inc(RecIdx);
      if RecIdx<>DelIdx then write(ChemDatH,Chem)
      end;
   
    closefile(ChemDat);
    closefile(ChemDatH)
  end;

  procedure RebuildDataFile;
  begin
    assignfile(ChemDat,Dateiname+'.dat');
    rewrite(ChemDat);

    assignfile(ChemDatH,'Hilf');
    reset(ChemDatH);

    while not(eof(ChemDatH)) do begin
      read(ChemDatH,Chem);
      write(ChemDat,Chem);
      end;

    closefile(ChemDat);
    closefile(ChemDatH);

    erasefile(ChemdatH)
  end;

  procedure RefillGrid;
  var i : Integer;
  begin
    assignfile(ChemDat,Dateiname+'.dat');
    reset(ChemDat);

    for i:=1 to FileSize(ChemDat) do begin
      read(ChemDat,Chem);
      with StringGrid1 do
        with Chem do begin
          Cells[0,i1]:=Format('%.3d',[i]);
          Cells[1,i1]:=IntToStr(BNum);
          Cells[2,i1]:=Name;
          Cells[3,i1]:=IntToStr(Bestand);
          Cells[4,i1]:=Datum
          end
      end;

    closefile(ChemDat);
  end;

begin
  DelPos:=NamePos(EditName.Text);
  if DelPos>=0 then begin
    DeleteRecord(DelPos);
    RebuildDataFile;
    RefillGrid
    end
end;
Wesentlicher Unterschied ist vielleicht, das die Prozedur in mehrere "Häppchen" unterteilt ist. Das ist in diesem Fall vielleicht übertrieben, hilft aber immer, den Überblick zu behalten und Fehler zu vermeiden oder schneller eingrenzen zu können. Auch werden die Dateien in jeder Funktion/Prozedur geöffnet und wieder geschlossen. Auch das vermeidet Fehler. Das assignfile() müsste natürlich nicht jedesmal wieder erfolgen, schadet aber auch nicht. Es gibt für den Grad der Unterteilung wohl kein RICHTIG und FALSCH, das muss jeder für sich entscheiden.

Den Code konnte ich nicht testen, da es ja nur ein Ausriss ist. Würde mich auch wundern, wenn gar kein "Fehlerchen" drin ist. Aber wenn, dann sollte er schnell zu entdecken sein. Lass mich mal überraschen, ob es dir hilft...
:hi:

PS: Meine Codeformatierung weicht vom Standard ab. Das mache ich aber schon so lange so, dass ich in meinem Alter davon nicht mehr abweichen mag

klausmaus 6. Okt 2008 21:49

Re: StringGrid Zeile per Mausclick auslesen
 
@ taaktaak

Großes Dankeschön für deine Mühe. Kann das Ganze aber leider erst am WE testen (büffel z. Zt. für `ne Klausur).
Melde mich, sobald ich ein Ergebnis habe.

Schönen Abend noch!

Michael

PS: Deine Formatierung erscheint mir logischer, aber da der Empfänger des Proggis die Formatierung so möchte, mach ich es halt so.

PPS: Habe in einigen Tagen das 46. Jahr geschafft.
Und jetzt gehts in die Heia.

klausmaus 9. Okt 2008 23:37

Re: StringGrid Zeile per Mausclick auslesen
 
Guten Morgen Ralph,

die Neugier hat mich nicht losgelassen. Du hattest recht, mit ein paar kleinen Änderungen läuft deine Prozedur prima durch. Habe noch ein kleines Problem, für das ich nach 3 Stunden probieren noch keine Lösung habe:
Beim Refill wird der dem gelöschten Datensatz nachfolgende Datensatz doppelt im StringGrid ausgegeben. In der Rebuild-Datei (und auch in 'Hilf') ist alles i.O.
Beim Schließen der Datei lasse ich das StringGrid entsprechend der Anzahl der Einträge leeren. Wg. dem doppelten Datensatz bleibt dann aber der letzte im StringGrid stehen und ist dann beim erneuten öffnen der Datei natürlich immer noch da.

Wäre super, wenn du mir noch ein letztes Mal helfen könntest. Irgendwie bin ich blind und finde den Fehler nicht. Meines Erachtens sollte er ja in der Refill-Prozedur stecken.

Nachfolgend der aktuelle Quelltext deiner Löschprozedur. Die kommentierten Zeilen habe ich geändert.
Delphi-Quellcode:
procedure TForm1.DatenLoeschenClick(Sender: TObject);
  var DelPos : Integer;
      ChemDatH : TChemDat;                    //nicht mehr global

  function NamePos(Name:String):Integer;
  begin
    Result:=-1;

    //assignfile(ChemDat,Dateiname+'.dat');   //Fehlermeldung - nach auskommentieren i.O.
    reset(ChemDat);

    while not Eof(ChemDat) do begin
      read(ChemDat,Chem);
      if Chem.Name=Name then begin
        Result:=FilePos(ChemDat)-1;   //Filepos -1 (löscht sonst nachfolgenden Satz)
        Break
        end
      end;
    closefile(ChemDat)
  end;

  procedure DeleteRecord(DelIdx:Integer);
  var RecIdx : Integer;
  begin
    //assignfile(ChemDat,Dateiname+'.dat');      //Fehlermeldung - nach auskommentieren i.O.
    reset(ChemDat);

   assignfile(ChemDatH,'Hilf');
    rewrite(ChemDatH);

    RecIdx:=-1;
    while not Eof(ChemDat) do begin
      read(ChemDat,Chem);
      inc(RecIdx);
      if RecIdx<>DelIdx then
      begin
      write(ChemDatH,Chem)
      end;
     end;
    closefile(ChemDat);
    closefile(ChemDatH);    
  end;

  procedure RebuildDataFile;
  begin
    assignfile(ChemDat,Dateiname);  //+'.dat' entfernt , da er sonst lauter dat anhängt
    rewrite(ChemDat);

    assignfile(ChemDatH,'Hilf');
    reset(ChemDatH);

    while not(eof(ChemDatH)) do begin
      read(ChemDatH,Chem);
      write(ChemDat,Chem);
      end;

    closefile(ChemDat);
    closefile(ChemDatH);

   // erase(ChemdatH)    nur auskommentiert, um Inhalt zu checken
  end;

  procedure RefillGrid;
  var i : Integer;
  begin
    assignfile(ChemDat,Dateiname);
    reset(ChemDat);

    for i:=1 to FileSize(ChemDat) do begin
      read(ChemDat,Chem);
      with StringGrid1 do
        with Chem do begin
          Cells[1,i]:=IntToStr(BNum);
          Cells[2,i]:=Name;
          Cells[3,i]:=IntToStr(Bestand);
          Cells[4,i]:=Datum
          end
      end;
    closefile(ChemDat);
  end;

begin
  DelPos:=NamePos(EditName.Text);
  if DelPos>=0 then begin
    DeleteRecord(DelPos);
    RebuildDataFile;
    RefillGrid
    end ;

      EditNr.Clear;
      EditName.Clear;
      EditZugang.Text:=IntToStr(0);
      EditAbgang.Text:=IntToStr(0);
      DateTimePicker1.Date:=Date();
  end;
Übrigens habe ich deine Prozedur zum Anlass genommen, das Programm zu überarbeiten. Mittlerweile ist mir klar, warum das Proggi, je länger es wurde, umso mehr Fehlermeldungen produzierte. Habe rigoros reset und closeFile benutzt. Und schon verringerte sich die Fehlerzahl.

Beste Grüße
Michael

PS: hatte beim nochmaligen durchlesen gerade `ne Idee fürs RefillGrid: vorher alles leeren(habe RowCount festgelegt). Dann sollte es doch leer sein. Probiere es aber erst heute nachmittag aus.

taaktaak 10. Okt 2008 07:05

Re: StringGrid Zeile per Mausclick auslesen
 
Guten Morgen Michael.

Freut mich, dass ich dir schon etwas weiterhelfen konnte. Die Anzeige der überflüssigen Zeile im Grid ist logisch, da ich es im Code leider nicht berücksichtigt habe.

Das Grid verhält sich allerdings anders, als man vielleicht erwartet: Durch Verringerung von RowCount werden die Inhalte der reduzierten Zeilen nicht gelöscht. Vergrößert man RowCount anschließend wieder, werden die vermeintlich entfernten Zeileninhalte wieder angezeigt. Tatsächlich gelöscht werden Einträge mit "StringGrid.Rows[..].Clear".

In deinem konkreten Fall gibt es (wie fast immer) verschiedene Möglichkeiten, das gewünschte zu erreichen. Als "Hau-Ruck-Methode" könnte man vor dem erneuten Füllen des Grids alle vorhandenen Zeilen löschen, die Zeilenanzahl des Grids aber konstant lassen.

Delphi-Quellcode:
procedure RefillGrid;
var i : Integer;
begin
  assignfile(ChemDat,Dateiname);
  reset(ChemDat);

  with StringGrid1 do begin

    for i:=FixedRows to RowCount-1 do Rows[i].Clear; // löscht ALLE Zeilen
    // oder
    // RowCount:=RowCount-1;                        // alternativ

    for i:=1 to FileSize(ChemDat) do begin
      read(ChemDat,Chem);
      with Chem do begin
        Cells[1,i]:=IntToStr(BNum);
        Cells[2,i]:=Name;
        Cells[3,i]:=IntToStr(Bestand);
        Cells[4,i]:=Datum
        end
    end;
  closefile(ChemDat);
end;
Alternativ könnte die Zeilenanzahl immer exakt der Anzahl der Datensätze+FixedRows entsprechen, d.h. nach einer Löschoperation "RowCount:=RowCount-1". Ich mag es aber z.B. nicht, wenn weniger Gridzeilen gezeichnet werden, als bei der verfügbaren Höhe des Controls darstellbar wären. In diesem Fall füge ich immer eine entsprechende Anzahl von Leerzeilen ein - aber das ist Geschmackssache.

Mich würde mal interessieren, wieviele Datensätze in deinem Grid voraussichtlich gespeichert werden sollen. Spätestens, wenn du einige Tausend Datensätze im Grid sortieren oder filtern möchtest, wirst du die begrenzten Möglichkeiten des StringGrids an spürbar langen Sortierzeiten erkennen. Wenn derartige Größenordnungen bei dir anfallen, dann sollte das ganze entweder mit einer Datenbank gelöst oder die Datenspeicherung in einer Liste erfolgen und das Grid nur noch zur Anzeige der sichtbaren Daten genutzt werden.

klausmaus 10. Okt 2008 13:52

Re: StringGrid Zeile per Mausclick auslesen
 
Hallo Ralph,

zu deiner Frage. Ich schrieb am Anfang, dass ich ein Newbie bin. Und zwar absolut. Da ich mit dem Rechner einigermaßen umgehen und ihn auch mal reparieren kann (selbst angeeignet) hab ich beschlossen, berufsbegleitend Informatik zu studieren. Im 2.Semester war Delphi das Thema (1.Semester LOGO). Vorlesung und Seminar im Wechsel. Hauptinhalt: Algorithmierung. Umsetzung in Quelltext sollte in Hausarbeit erfolgen. Hinweis der Seminarleiter: Wenn sie was nicht wissen, nutzen sie die Hilfe (Delphi 2005). Daher rühren auch meine zum Teil naiven Fragen, da diese "Hilfe" nur wenig hilft.

Als Beleg sollte über die Semesterpause ein Programm zu einem selbstgewählten Thema/Inhalt angefertigt werden. Vorgabe: Einbinden von Dateiarbeit (wurde im letzten Seminar kurz angeschnitten).

Meine Kommilitonen haben größtenteils mathemat. Hintergrund. Ergo: Mathematische Berechnungen. Da ich aus der Chemie komme, hab ich mich für eine Chemikalienbestandsverwaltung entschieden. Normalerweise sollte das eine Datenbank sein. Da wir so was noch nie gemacht haben (und freies Delphi keine DB-Komponente enhält) blieb nur ein StringGrid.

Ich habe es auf 200 Datensätze ausgelegt. Also recht klein.
Verwenden werde ich das Programm nicht - es gibt recht gute und viel komfortablere Lösungen (auch kostenfrei) am Markt.

Ich habe es als Übung angesehen, um sich mit Delphi als Programmierwerkzeug vertraut zu machen. Ich hätte allerdings nicht gedacht, dass es so viel Zeit kostet (arbeite seit Ende Sommersemester dran). Lag vermutlich an meinerseits nicht vorhandener Projektplanung. Im Laufe der Entwicklung wurde es auch immer umfangreicher.

Wenn ich das Ganze nicht nächste Woche abgeben müsste, würde ich glatt nochmal von vorn anfangen und vieles anders machen. Stattdessen hab ich mit Hilfe deiner Tipps etwas Struktur in den Quelltext gebracht.

Werde mich am WE mal mit dem Abfangen von Fehleingaben weiter beschäftigen. (Ist auch eine Forderung für den Beleg).

Wie du siehst: Noch reichlich Arbeit. Bin aber froh, dass es im Großen und Ganzen funktioniert.

Wünsche ein angenehmes WE
Michael


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:14 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