Entwickler-Ecke
Delphi Language (Object-Pascal) / CLX - Bei Fehler Programm anhalten und in Ausgangszustand zurück
Krischa - Di 09.06.09 09:39
Titel: Bei Fehler Programm anhalten und in Ausgangszustand zurück
Hi,
ich starte mit einem Button-Click eine Ansammlung von Datenbankabfragen. Ich überprüfe bei jeder Abfrage ob das Feld das er ausliest leer ist.
Delphi-Quelltext
1:
| if query1.fieldbyname('Name')<>NULL then ... |
Wenn das Feld jetzt leer ist gibt er mir eine MessageBox aus in welcher Datenbank der Wert fehlt. Nach der MessageBox soll er nun den Programmcode nicht weiter abarbeiten und in den Ausgangszustand zurück gehen (vor dem Drücken des Buttons). Wie kann ich das machen?
jaenicke - Di 09.06.09 09:45
Dafür musst du den Zustand vorher speichern. Es gibt nicht irgendwie eine "Undo"-Funktion oder sowas. Wie auch?
oki - Di 09.06.09 09:48
Am Besten alles, was du bis dahin gemacht hast zurücksetzen. Ich schreib mir dafür immer eine Methode die im Namen was mit "Default" hat. Zum Start des Programms gibt es ja eigentlich ein Sammelsurium von Einstellungen für Buttons, Datenbankzustand usw. Die setze ich dann explizit.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| procedure SetDefaultItems; begin MyButton.Enabled := True; if MyTable1.Open then MyTable1.Close; ... end; |
Diese Methode rufst du dann auf und alle ist wie vorher.
Manno eh, jaenicke war schneller :cry:
Gruß oki
Krischa - Di 09.06.09 09:49
Mir würde schon reichen wie ich ihn dazu kriege das Programm anzuhalten und nicht weiter durch zu laufen.
jaenicke - Di 09.06.09 09:50
Suchst du vielleicht Exit? Das springt aus der aktuellen Prozedur raus.
Krischa - Di 09.06.09 09:54
Ja, das Exit reicht mir. :)
[Edit]Habe gerade festgestellt exti reicht doch nicht. Es beendet ja nur die aktuelle Funtkion. Aber da ich zwischen mehreren Funktion springe soll er alle beenden. [/Edit]
glotzer - Di 09.06.09 11:43
[ironi] wie wärs mit Application.Terminate ? [/ironi]
jaenicke - Di 09.06.09 11:44
Dann löse eine Exception aus und fange die in der obersten Ebene mit try..except ab, die nicht mehr abgebrochen werden soll.
Delphi-Quelltext
1:
| raise Exception.Create('Oooops'); |
Am besten mit einer eigenen Exceptionklasse mit weiteren Details.
zuma - Di 09.06.09 12:15
Wie wäre es, wenn du dir alle Prüfungen in einer Stringlist merkst (Name/Value-Eigenschaften nutzen ala Feld=Wert), somit kannst du durchlaufen lassen, am Ende dann die Liste durchlaufen, die Values prüfen und evtl. alle leeren Felder auf einmal anzeigen.
in etwa so:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| if not query1.fieldbyname('Name') <> NULL then lFehlerListe.Add('Name='+query1.fieldbyname('Name').AsString); ...
s := ''; for i := 0 to lFehlerliste.count -1 do if lFehlerliste.ValueFromIndex[i] = '' then s := s + lFehlerliste.Names[i] + 'ist leer'+#13+#10; if s <>'' then showmessage(s); ... |
Stelle mir vor, das das u.U. bequemer ist, als 'nach und nach' rauszufinden, wo noch ein Feldwert fehlt ...
Gehts dir allerdings bei deinem Abbruch um Performance, so hilft dir mein Lösungsansatz leider nicht.
Krischa - Mi 10.06.09 08:38
Mit dem Exception auslösen hat es prima funktioniert. Wusste garnicht das man die von Hand auslösen kann.
@glotzer deine "ironi" kannst du dir sparen. Ich wollte nicht das ganze Programm beenden sondern nur die Buttonklick-Routine mit all ihren Unterfunktionen
Danke für eure Hilfe
oki - Mi 10.06.09 09:02
Soory, aber ich halte die Benutzung einer Exzeption für einen regulären Abbruch einer Funktion nicht unbedingt für elegant. Nun kann man sicher über das Thema "Elegant" trefflich streiten, aber ich sehe den Einsatz von Exception als ein Mittel um auf Fehler und Ausnahmeereignisse zu reagieren. In 99% der Fälle wird das auch so sein. Der eine Fall für einen ordnungsgemäßen Abbruch des Ablaufes dann von einem echten Fehler zu unterscheiden ist im Zweifelsfall eher problematisch. Dann doch einfach Exit. Das bewirkt das gleiche, die Funktion wird beendet ohne weiteren Code der Funktion abzuarbeiten. Will man das auch in etwaigen Schleifen tun, so kann man sich eine "globale" Break-Variable anlegen, die bei Click auf einen Abbrechen-Button auf True gesetzt wird. In den entsprechenden Schleifen implementiert man ein Application.ProcessMessages und prüft die Variabel. Ist sie True, dann Exit. Das kann man auch in jede Subroutine implementieren.
Am Ende der Hauptprocedure die abgearbeitet wird setzt man die Variable wieder auf False. Um das auch bei einem Exit hinzubekommen kann man den gesamten Code der procedure in einen try finally Block kapseln. Glücklicherweise wird bei einem Exit nämlich der Code im finally Abschnitt immer ausgeführt.
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:
| var FUserBreak : Boolean; .... procedure DoIt; var Counter : Integer; begin try for Counter := 0 to 100000 do begin Application.ProcessMessages; if FUserBreak then Exit; end; ...... finally if FUserBreak then begin FUserBreak := False; SetDefault; end; end; end;
FUserBreak := True; |
Gruß oki
Krischa - Mi 10.06.09 09:06
Mein Problem mit Exit; ist aber das es nur die aktuelle Funktion beendet. Wenn aber diese durch eine andere gestartet wird, wird die aufrufende Funktion zu ende bearbeitet und das soll sie bei mir nicht.
oki - Mi 10.06.09 09:12
Dann implementiere die Subfunktionen als Funktionen mit Boolean als Rückgabewert. Frage auch in diesen Procedure an geeigneter Stelle (muss ja nicht hinter jeder CodeZeile sein, reicht oft am Ende) FUserBrake ab oder setze einfach Result := not FUserBrake. Gibt die Funktion False zurück machst du das Exit. Das kann dann auch wieder in den try finally, der dann wiederum Result auf not FUserbraek setzt. So kannst du endlos verschachteln. Die Funktionsaufrufe müssen dann natürlich ausgewertet werden.
Das ist dann sicher auch nicht immer die elegante Lösung. Kommt auf den Code an. Musst du aber eine echte Exception mit einem try except Block behandeln und willst dann nicht abbrechen bekommst du ein Problem mit deiner Abbruchexception, so sie sich im gleichen Block befindet.
Gruß oki
jaenicke - Mi 10.06.09 09:27
Deshalb meinte ich ja, am besten wäre eine eigene Exceptionklasse, damit man den Typ der Ausnahme feststellen kann in except. Nämlich, ob der eigene Fehler oder ein anderer aufgetreten ist.
Prinzipiell ist eine Exception durchaus für den Zweck gut geeignet, denn eine Exception soll genau einen solchen Fehler signalisieren. Und anders als mit einem boolschen Wert kann man auch Details dazu in einer eigenen Exceptionklasse mitliefern. Man muss das allerdings auch sauber umsetzen um keine Speicherlecks zu hinterlassen.
oki - Mi 10.06.09 10:00
Hi jaenicke,
klar ist das ein gangbarer Weg. Ich denke, hier gilt wieder die alte Regel, viele Wege führen nach Rom. Welcher nun der geeignetere ist liegt sicher am Aufbau des konkreten Projektes sowie des Geschmacks des Programmierers. Meine Abneigung eine Exception zu verwenden tendiert definitiv zur Geschmacksecke. Meine Variante hat natürlich auch ihre Nachteile. Will ich Funktionen mit Rückgabewerten verwenden, dann ist Result auch schon "verbraucht". Die dann als var-Parameter zurückzuliefern ist auch nicht das gelbe vom Ei. Man muss also immer schauen was sinnvoll ist. Eigentlich wollte ich nur einen anderen Weg vorstellen und nicht gegen die eigene Exception intervenieren.
Gruß oki
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2026 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!