![]() |
Probleme mit u.a. Timern in Array
Hallo,
ich habe ein Programm, das Records mit verschiedene Daten und einen Timer in einem dynamischen Array ablegt. Zu jedem Record wird auch ein Menü-Item angelegt. Wenn nun mehr als 2 Records vorhanden sind, gibt es beim Beenden des Programms verschiedene Fehler (Exception, Runtime Error) bzw. seit neuestem (kann auch daran liegen, dass ich das Programm nicht mehr so lange laufen lasse) ungültige Zeigeroperation. Die Fehlermeldungen kommen nicht in meinem eigenen Code, sondern nach dem, was in onFormDestroy ausgeführt wird. Jetzt habe ich drei Fragen:
Ich kann gerne etwas Code einstellen, müsste aber wissen, von welcher Stelle. |
Re: Probleme mit u.a. Timern in Array
Hallo,
also mich würde mal die Freigebe-procedure interessieren. Zudem: Es ist nicht nötig, die Länge des Arrays zu verkürzen. Die wird am Ende eh auf 0 gesetzt und behindert dich hier nur. Ein SetLength:=0 sollte man meiner Meinung nach nicht machen, da wird ja nichts freigegeben. MfG Regan |
Re: Probleme mit u.a. Timern in Array
Hmm, meinst du beim Löschen? Dann habe ich ja eine "Datenleiche", wenn ich einen weiteren Record hinzufüge.
Die Lösch-Procedure. Es geht übrigens um E-Mail-Konten, MKonten ist das Array of Record.
Delphi-Quellcode:
function KontoLoeschen(lID: Cardinal): Boolean;
var I: Cardinal; begin result := false; { außerhalb } If not (lID in [Low(MKonten)..High(MKonten)]) then exit; { 0 Einträge } result := (Length(MKonten) > 0); if not result then exit; { 1 Eintrag } If (Length(MKonten) = 1) then begin result := (lID = 0); if (Result) then begin FreeAndNil(MKonten[lID].ITimer); SetLength(MKonten, 0); exit; end; end; { 2+ Einträge } FreeAndNil(MKonten[lID].ITimer); { -> verschieben und Rest eins hochrücken } case (High(MKonten) - lID) of 0: SetLength(MKonten, High(MKonten)); 1: begin MKonten[Pred(High(MKonten))] := MKonten[High(MKonten)]; SetLength(Mkonten, Pred(High(Mkonten))); end; else begin for I := lID to (Length(MKonten) - 2) do MKonten[I] := MKonten[Succ(I)]; SetLength(MKonten, Pred(Length(MKonten))); end; end; result := true; { MenuItem suchen und löschen } for I := Pred(MCForm.M_Check.Count) downto 0 do if (MCForm.M_Check.Items[I].Tag = Succ(lID)) then MCForm.M_Check.Delete(I); end; |
Re: Probleme mit u.a. Timern in Array
Delphi-Quellcode:
Edit:
function KontoLoeschen(lID: Cardinal): Boolean;
var I: Cardinal; begin result := false; { außerhalb } If not (lID in [Low(MKonten)..High(MKonten)]) then exit; (* wird bereits durch die vorherige Bedingung abgedeckt { 0 Einträge } result := (Length(MKonten) > 0); if not result then exit; *) (* überflüssige Sonderbehandlung { 1 Eintrag } If (Length(MKonten) = 1) then begin result := (lID = 0); if (Result) then begin FreeAndNil(MKonten[lID].ITimer); SetLength(MKonten, 0); exit; end; end; *) { 2+ Einträge } (* Free reicht eigentlich, der Eintrag wird sowieso gleich überschrieben *) FreeAndNil(MKonten[lID].ITimer); { -> verschieben und Rest eins hochrücken } (* überflüssige Sonderbehandlung case (High(MKonten) - lID) of 0: SetLength(MKonten, High(MKonten)); 1: begin MKonten[Pred(High(MKonten))] := MKonten[High(MKonten)]; SetLength(Mkonten, Pred(High(Mkonten))); <- FEHLER ein Element zu viel gelöscht end; else begin for I := lID to (Length(MKonten) - 2) do MKonten[I] := MKonten[Succ(I)]; SetLength(MKonten, Pred(Length(MKonten))); end; end; *) for I := lID to (Length(MKonten) - 2) do MKonten[I] := MKonten[Succ(I)]; SetLength(MKonten, Pred(Length(MKonten))); result := true; { MenuItem suchen und löschen } for I := Pred(MCForm.M_Check.Count) downto 0 do if (MCForm.M_Check.Items[I].Tag = Succ(lID)) then MCForm.M_Check.Delete(I); end; Was passiert eigentlich mit dem Tag der nachfolgenden Menüelemente, müsste der nicht auch angepasst werden? |
Re: Probleme mit u.a. Timern in Array
Du könntest statt Records Klassen verwenden, die den Timer selbst beim Zerstören der Instanz sauber freigeben. Dann könntest du auch eine TObjectList verwenden mit OwnsObjects auf True und müsstest dich um die Freigabe nicht mehr kümmern. Dann müsstest du nur noch einmal Delete aufrufen um einen Eintrag zu zerstören. Das würde sehr viel Arbeit abnehmen.
Ein Timer innerhalb eines Records in einem dynamischen Array hört sich allerdings nach einem recht seltsamen Konstrukt an, vielleicht wäre da ein besseres Konzept sinnvoll. |
Re: Probleme mit u.a. Timern in Array
Danke für den Tipp, damit werde ich mich mal beschäftigen, das hört sich sehr gut an.
Auf die "seltsame Konstruktion" bin ich gekommen, weil im onTimer jeweils der Aufruf der Prüfprozedur (Anzahl E-Mails) erfolgt. Ich wollte ursprünglich nur einen einzelnen Timer für alle Konten verwenden, allerdings hätte das Probleme gegeben, wenn z.B. die Prüfprozedur aufgerufen wird und im nächsten Durchlauf schon wieder ein anderes Konto aufrufen müsste, bevor die letzte Prüfung fertig war. Kann aber auch ein Denkfehler sein, denn ausprobiert habe ich es noch nicht. @Blup: Den Tag nehme ich nur als fortlaufenden Index, der nicht der Position des Kontos im Array entspricht (sonst müsste ich den bei jedem Löschen auch verändern). Der Tag ist mit dem des Timers identisch, dadurch kann ich allen Timern das gleiche Event zuweisen und darin das Konto ermitteln:
Delphi-Quellcode:
Dann werde ich mich jetzt mal an die Überarbeitung der Lösch-Procedure bzw. die ObjectList machen :)
procedure TMCForm.PostPruefenAufruf(Sender: TObject);
begin PostPruefen(Pred(TTimer(Sender).Tag)); end; |
Re: Probleme mit u.a. Timern in Array
Zitat:
|
Re: Probleme mit u.a. Timern in Array
Zitat:
Zumindest um den Timer zusammen mit dem Eintrag im Array zu löschen. Wenn diese nicht mit dem Tag des Timer und des MenuItem übereinstimmt, dann muss dieser Tag aus dem Timer ermittelt werden, um das richtige Menüitem zu löschen.
Delphi-Quellcode:
function KontoMenuLoeschen(lTag: Cardinal): Boolean;
var i: Integer; begin { MenuItem suchen und löschen } for i := Pred(MCForm.M_Check.Count) downto 0 do begin Result := (MCForm.M_Check.Items[i].Tag = lTag); if Result then begin MCForm.M_Check.Delete(i); Exit; end; end; Result := False; end; {...} KontoMenuLoeschen(MKonten[lID].ITimer.Tag); FreeAndNil(MKonten[lID].ITimer); {...} |
Re: Probleme mit u.a. Timern in Array
Stimmt, du hast Recht - da war noch ein großer Denkfehler :wall:
|
Re: Probleme mit u.a. Timern in Array
Die Konten werden nun in einer ObjectList gespeichert und das Problem mit dem Index ist auch behoben - danke für die Tipps :thumb:
Beim Beenden kommt immer noch eine Ungültige Zeigeroperation. Und zwar in einem onTimer. Den Timer lasse ich jede Sekunde die Restzeit bis zur nächsten Prüfung für jedes Konto berechnen - soviel zur Erklärung. Ich habe jetzt probiert, eine Variable beim Beenden (Klicken im Menü oder Message von Windows) auf true zu setzen. Am Anfang der Timer-Prozedur und in der Schleife prüfe ich die Variable und verlasse das ggf. per break/exit. Trotzdem kommt die Meldung. Wenn ich alles in der Timer-Prozedur auskommentiere, funktioniert es. Woran kann denn das jetzt noch liegen? :gruebel: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:58 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