TCheckBox und seine Tücken

Für Fragen von Einsteigern und Programmieranfängern...
BernhardDEL
Beiträge: 36
Registriert: Di 31. Jan 2017, 17:18

TCheckBox und seine Tücken

Beitrag von BernhardDEL »

Hallo zusammen.

Mal wieder brauche ich ein wenig Hilfe.

Habe in meinem Programm zwei TCheckBox Komponenten mit 9 bzw. 12 Checkboxen.
Nun will ich beim Beenden des Programms abspeichern, welche Boxen gecheckt sind und welche nicht,
damit beim Starten des Programms der alte Zustand wieder hergestellt werden kann.

Leider hab ich noch nicht herausgefunden, wie das gehen soll. Der in meinem Buch beschriebene Weg funktioniert leider nicht.
Dort ist zu finden :
............................."if CheckGroup1.Items.Checked[2] then ......."
Das geht leider nicht. Items.Checked[2] ist unbekannt.

Bei mir sieht das so aus :

For x := 0 to GFsKlasse.Items.Count-1 do
if GFsKlasse.checked[x] then
temp.FsKlasse.Checked[x] := true;

Geht auch nicht.

Irgendwie muss man doch abfragen können, ob gecheckt ist oder nicht und auch den Checkpoint über das Programm steuern können.

Oder ?????

Schönen Sonntag noch

Bernhard

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TCheckBox und seine Tücken

Beitrag von Mathias »

Dies wäre der einfachste Weg, einfach der checke-Status der CheckBox abspeichern.

Code: Alles auswählen

var
  ini: TIniFile;
begin
  ini := TIniFile.Create('test.ini');
  ini.WriteBool('CheckBox', 'cb1,', CheckBox1.Checked);
  ini.Free;
end;   


Beim Laden einfach der umgekehrte Weg.

Code: Alles auswählen

  CheckBox1.Checked := ini.ReadBool('CheckBox', 'cb1,', False);



Habe in meinem Programm zwei TCheckBox Komponenten mit 9 bzw. 12 Checkboxen.

Dieser Satz verstehe ich nicht. :roll:

Meinst du etwa damit eine GroubBox mit CheckBoxen ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: TCheckBox und seine Tücken

Beitrag von wp_xyz »

Ich nehme an, du hast CheckGroup-Komponenten auf dem Formular. Hier kannst du über CheckGroup.Checked[i] (nicht: CheckGroup.Items.Checked[i] !) abfragen, ob die Checkbox mit Index i gesetzt ist. Um den Check-Zustand in die Ini-Datei zu schreiben, würde ich folgendes machen:

Code: Alles auswählen

procedure TForm1.IniSchreiben;
var
  ini: TIniFile;
begin
  ini := TIniFile.Create(GetAppConfigFile(false));
  try
    for i:=0 to Checkgroup1.Items.Count-1 do
      ini.WriteBool('CheckGroup1', 'Item' + IntToStr(i), CheckGroup1.Checked[i];
  finally
    ini.Free;
  end;
end;

Um das beim Programmstart wieder einzulesen, rufst du dieses auf:

Code: Alles auswählen

procedure TForm1.IniLesen;
var
  ini: TIniFile;
begin
  ini := TIniFile.Create(GetAppConfigFile(false));
  try
    for i:=0 to Checkgroup1.Items.Count-1 do
      Checkgroup1.Checked[i] := ini.ReadBool('CheckGroup1', 'Item' + IntToStr(i), CheckGroup1.Checked[i]);
  finally
    ini.Free;
  end;
end;

Statt 'Item' + IntToStr(i) kannst du auch den der Checkbox zugeordneten Text in die Ini-Datei schreiben:

Code: Alles auswählen

...
  ini.WriteBool(Checkgroup1.Caption, CheckGroup1.Items[i], CheckGroup1.Checked[i]);
  // bzw, zum Lesen
  CheckGroup1.Checked[i] := ini.ReadBool(Checkgroup1.Caption, Checkgroup1.Items[i], CheckGroup1.Checked[i]);
 

Das ganze ist nicht getestet, muss aber vom Prinzip her funktionieren. Falls irgendwas nicht geht, schreib bitte nicht "Funktioniert auch nicht", sondern was genau passiert. Sonst kann dir niemand helfen.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TCheckBox und seine Tücken

Beitrag von Mathias »

GetAppConfigFile würde ich nur verwenden, wen es notwendig ist, oder hast du gerne, wen Datei-Leichen rumliegen ?
Ich würde die Datei in den Ordner speichern, dort wo auch die project1 ist.

Ausser man schreibt etwas professionelles, dann sieht die anders aus.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

BernhardDEL
Beiträge: 36
Registriert: Di 31. Jan 2017, 17:18

Re: TCheckBox und seine Tücken

Beitrag von BernhardDEL »

Hmm - scheint doch nicht so einfach zu sein, kann aber auch sein, dass ich mich unverständlich ausgedrückt habe.
Hier mal erwähnt, dass auf dem Panel noch andere Eingabefelder sind, die ich zusammen mit den beiden TCheckGroup-Komponenten
in eine Datei (record) schreiben will. Hierzu benötige ich aber nur den Status der einzelnen CheckBoxen.
Beim erneuten Laden soll dann alles in die einzelnen Komponenten auf dem Panel zurück geschrieben werden.
Die Sicherungsdatei befindet sich auf der Festplatte und zusätzlich auf einem USB-Stick, um sie gegebenfalls auf einem anderen Rechner
laden zu können.
Die Eingaben werden für mehrere Fahrer in eine Datei gespeichert.
Die Eingaben werden für mehrere Fahrer in eine Datei gespeichert.


Dazu der Quelltext :
mein Quelltext.JPG


Ja - habe einmal das -1 vergessen, aber nachdem ich den Fehler korrigiert habe kommt es auch weiter mit der nachstehenden Fehlermeldung zum Programmabbruch.
Fehlermeldung mit dem Quelltext, der mir dann angezeigt wird :
Fehler1.JPG
Fehler1.JPG (19.36 KiB) 3011 mal betrachtet

Fehler2.JPG

Das Abspeichern der Daten selbst klappt - wenn ich das mit den CheckBoxen ausklammere.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TCheckBox und seine Tücken

Beitrag von Mathias »

Wieso erweiterst du nicht deinen Record temp nicht um die Element B, C, D1,.. : Boolean; ?

Code: Alles auswählen

  temp.B := CheckBoxB.checked;
  temp.C := CheckBoxC.checked;
  temp.D1 := CheckBoxD1.checked;
  .....


So nebenbei, wieso verwendest du bei Gefahrengut keine RadioButton, anstelle von CheckBoxen ?
Sind da mehrere Klassen auf einmal möglich ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

BernhardDEL
Beiträge: 36
Registriert: Di 31. Jan 2017, 17:18

Re: TCheckBox und seine Tücken

Beitrag von BernhardDEL »

Mathias hat geschrieben:Wieso erweiterst du nicht deinen Record temp nicht um die Element B, C, D1,.. : Boolean; ?

Code: Alles auswählen

  temp.B := CheckBoxB.checked;
  temp.C := CheckBoxC.checked;
  temp.D1 := CheckBoxD1.checked;
  .....

Hab ich mir auch schon mal überlegt und werde es jetzt auch versuchen. Danke.

Mathias hat geschrieben:So nebenbei, wieso verwendest du bei Gefahrengut keine RadioButton, anstelle von CheckBoxen ?
Sind da mehrere Klassen auf einmal möglich ?

Ja, es fehlen auch in der Aufstellung die Klassen 1 (radioaktive Ladung) und 7 (Sprengstoffe).
Normalerweise werden die hier aufgeführten Klassen zusammen gemacht, theoretisch kann man aber jede Klasse für sich erwerben,
was aber wenig sinnvoll ist. Darum erfolgt auch keine Ausgliederung im Bereich "Tank". Es wäre blöd für Benzin und Diesel die
Berechtigung zu erwerben, aber für hochkalt verflüssigte Stoffe, wie z.Bsp. Sauerstoff, Stickstoff oder Wasserstoff, es nicht zu tun.
Problematisch wird es vor Sylvester, wenn man da einen Container mit Feuerwerkskörpern bekommt :oops: Normalerweise bräuchte
man dazu die Klasse 7, aber die Packer laden andere Ware mit bei, sodass man mit Klasse 9 (gemischtes oder sonstiges Gefahrgut) fahren kann.

knight
Beiträge: 802
Registriert: Mi 13. Sep 2006, 22:30

Re: TCheckBox und seine Tücken

Beitrag von knight »

Bevor du noch einen Polizeieinsatz auslöst: Die Gefahrgutklasse 7 ist die mit dem strahlenden Material. Damit würde ich definitiv kein Feuerwerk zünden wollen.

knight

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TCheckBox und seine Tücken

Beitrag von Mathias »

Die Gefahrgutklasse 7 ist die mit dem strahlenden Material.

Die 7 ist in seinem Dialog auch nicht vorhanden.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

BernhardDEL
Beiträge: 36
Registriert: Di 31. Jan 2017, 17:18

Re: TCheckBox und seine Tücken

Beitrag von BernhardDEL »

knight hat geschrieben:Bevor du noch einen Polizeieinsatz auslöst: Die Gefahrgutklasse 7 ist die mit dem strahlenden Material. Damit würde ich definitiv kein Feuerwerk zünden wollen.
knight


Hahaha, da magst Du recht haben. Ich weis schon, warum ich diese Klasse nicht habe :wink:
Die Klassen bring ich eh immer durcheinander. Wie gut, dass es schriftliche Weisungen gibt :lol:

Mathias - danke nochmal, ich habe es mit Array of Bool gemacht und es klappt.

Im Moment habe ich das Problem, dass er den ersten Datensatz in meinem File nicht findet.

Wenn ich zu Programmstart die Datei durchlaufe, um die Namen der Fahrer in die ComboBox einzulesen, ist alles noch OK.

Suche ich später aber nach dem ersten Datensatz, dann findet er ihn nicht mehr - und das, obwohl ich nichts anderes mache als vorher,
eben nur zu einem späteren Zeitpunkt.

Ich glaub, ich brauche eine Pause, damit ich aufhöre im Kreis zu denken.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TCheckBox und seine Tücken

Beitrag von Mathias »

Im Moment habe ich das Problem, dass er den ersten Datensatz in meinem File nicht findet.

Wie sind die Datensätze gespeichert ?
In einer Array ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

BernhardDEL
Beiträge: 36
Registriert: Di 31. Jan 2017, 17:18

Re: TCheckBox und seine Tücken

Beitrag von BernhardDEL »

Hier der Record. den ich abspeichere :

{Personaldaten}
TPersoRec = record
Zeitstempel : TDateTime;
Personr : Integer;
Name,Vorname,
Strasse,
Land,PLZ,Stadt,
gebLand,
FsNr,
FkNr : String[50];
FsKlasse : array[1..11] of Boolean;
GgKlasse : array[1..12] of Boolean;
ModuleGueltig,
FSGueltig,
GgGueltig,
FKGueltig,
geboren, Eintritt : TDate;
End;

Der wird vor dem Abspeichern gefüllt und dann in die Datei geschrieben :

Procedure PersoRec_schreiben(PersoRec : TPersoRec);
var
x : Integer = 0;

Begin
Assign(PersoDat,PersoPfad);
if not FileExists(PersoPfad) then // Datei ist nicht vorhanden
Begin
try
rewrite(PersoDat); // Datei neu erstellen
finally
close(PersoDat); // Datei schließen
end;
end;
x := PersoNr_suchen(PersoRec.PersoNr); // Datensatz per Personalnummer suchen
if x = 0 then
x := PersoName_suchen(PersoRec.Name); // Datensatz per Fahrername suchen
if x = 0 then // Datensatz nicht gefunden
Begin
try
Reset(PersoDat); // Datei öffnen
Seek(PersoDat,FileSize(PersoDat)); // an das Ende der Datei gehen
write(PersoDat,PersoRec); // Datensatz hinzufügen
finally
CloseFile(PersoDat); // Datei schließen
end;
End
else // Datensatz wurde gefunden
Begin
try
Reset(PersoDat); // Datei öffnen
Seek(PersoDat,x); // Zeiger auf Datensatz positionieren
write(PersoDat,PersoRec) // Datensatz überschreiben
finally
CloseFile(PersoDat); // Datei schließen
end;
end;
end;

Vom Prinzip her nicht anders, als beim Auflieger oder LKW, nur hier findet er erst ab dem zweiten Datensatz.

Ich habe zwei Suchroutinen, einmal nach Pers.Nr und einmal nach Name.

Function PersoName_suchen(Name : String): Integer;
var
X : Integer = 0;
temp : TPersoRec;
gefunden : Boolean = false;

Begin
Assign(PersoDat,PersoPfad);
PersoRecSauber(temp); // hier wird der Record inialisiert, Integer und Date mit 0, String mit '' und Bool mit false
if FileExists(PersoPfad) then // wenn die Datei existiert
Begin
try
reset(PersoDat); // Datei öffnen
While not EOF(PersoDat) do // Datei durchlaufen bis zum Ende
Begin
read(PersoDat,temp); // Datensatz lesen
Inc(x);
gefunden := temp.Name = Name; // Name vergleichen
if gefunden then // wenn gefunden
Begin
Result := x; //FilePos(PersoDat)-1; // Datensatzposition übergeben
exit; //Abbruch
end;
end;
finally
close(PersoDat); // Datei schließen
end;
end;
Result := x; // kein Datensatz
end;

Tja - und das lesen ist ja eigentlich auch kein Problem :

Function DatPerso_lesen(x : Integer): TPersoRec; // x ist die mit Func Suchen gefundene Position des Datensatzes in der Datei
var
temp : TPersoRec;

Begin
PersoRecSauber(temp);
Assign(PersoDat,PersoPfad);
if x > 0 then
if FileExists(PersoPfad) then
Begin
try
reset(PersoDat); // Datei öffnen
Seek(PersoDat,x); // Auf Datensatz positionieren
if not EOF(PersoDat) then
read(PersoDat,temp); // gewünschten Datensatz auslesen
finally
close(PersoDat); // Datei schließen
end;
end;
Result := temp; // gelesenen Datensatz zurückliefern
end;

Ich muss das Ganze nochmal mit meinen funktionierenden Routinen aus Auflieger und LKW vergleichen .
Vielleicht finde ich ja dann den Fehler.

BernhardDEL
Beiträge: 36
Registriert: Di 31. Jan 2017, 17:18

Re: TCheckBox und seine Tücken

Beitrag von BernhardDEL »

Entschuldige bitte meine vielleicht etwas adequate Programmierweise, jedoch bitte ich zu bedenken, dass
ich das Programmieren zu einer Zeit erlernt habe, da gab es noch kein Windows und objektorientierte Programmierung,
da war alles Ereignisorientiert und man musste noch zwischen Text und Graphik umschalten. :)
Was heute mit einem Mausklick erledigt ist haben wir noch von Hand geschrieben.
Die Routinen, die Lazarus für die Dateibehandlung zur Verfügung stellt sind sicher besser geeignet, jedoch fällt es mir
in meinem Alter etwas schwer mich mit der ganzen Geschichte auseinander zu setzen. Ich bin auch zu ungeduldig und
versuche lieber auf altes Wissen zurückzugreifen, was aber auch nur noch lückenhaft vorhanden ist. Man vergisst mit der
Zeit doch eine Menge.

Mathias
Beiträge: 6164
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: TCheckBox und seine Tücken

Beitrag von Mathias »

Entschuldige bitte meine vielleicht etwas adequate Programmierweise,

Dies ist weniger das Problem, aber könntest du den Code in Code-Tags nehmen, dann ist er leserlicher. :wink:

Noch ein Tip für die Boolean-Array, mit bitpacked wird deine Datei kleiner.

Code: Alles auswählen

var
  a1 :array[1..11] of Boolean;             // verbraucht 2 Byte
  a2 :bitpacked array[1..11] of Boolean;   // verbraucht 11 Byte
 
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

BernhardDEL
Beiträge: 36
Registriert: Di 31. Jan 2017, 17:18

Re: TCheckBox und seine Tücken

Beitrag von BernhardDEL »

Mathias hat geschrieben:
Entschuldige bitte meine vielleicht etwas adequate Programmierweise,

Dies ist weniger das Problem, aber könntest du den Code in Code-Tags nehmen, dann ist er leserlicher. :wink:

Sorry, mach ich.
Nachdem ich mich erfolglos auf die Fehlersuche gemacht habe bin ich vor lauter Verzweiflung hin gegangen und
habe es neu geschrieben. :shock: Alles so gemacht wie bei der LKW-Datei, wo es ja funktioniert.
Ergebnis: der gleiche Mist wie zuvor :( - er findet den ersten Datensatz nicht. Doch der steht definitiv in der Datei,
da er bein adden der TStrings in die Combobox gefunden wird. Und da laufe ich ja auch durch die Datei, so wie hier beim Suchen:

Code: Alles auswählen

var
Function  PersoNr_suchen(Text : String) : Integer;  Text ist die Personalnummer, die gesucht wird
var
   X        : Integer = 0;
   temp     : TPersoRec;
   gefunden : Boolean = false;
 
Begin
   Assign(PersoDat,PersoPfad);
   if FileExists(PersoPfad) then         // wenn die Datei existiert
   Begin
      try
         reset(PersoDat);                // Datei öffnen
         If not EOF(PersoDat) then       // es muss zumindest ein Datensatz da sein
         Begin
            While not EOF(PersoDat) do                                 // Datei durchlaufen bis zum Ende
            Begin
               read(PersoDat,temp);                                       // Datensatz lesen
               gefunden := temp.PersoNr = StrToInt(Text);       // Perso-Nummer vergleichen
               if gefunden then
               Begin
                  x := FilePos(PersoDat)-1;                               // wenn gefunden, dann Position merken (-1, weil ja der Zeiger nach dem read um eins nach oben versetzt wird)
                  seek(PersoDat,FileSize(PersoDat));                 // und Abbruchbedingung setzen
               end;
            end;
         end;
      finally
         close(PersoDat);             // Datei schließen
      end;
   end;
   Result := x;                          // Datensatzposition übergeben
end;                                       // gefunden = > 0, nicht gefunden = 0
 


Wo bitte ist mein Fehler ??? :cry: :cry: :cry: :?:

Antworten