Autor |
Beitrag |
Fienix
Beiträge: 109
Win 2K, Win XP Pro, Win 7
D 5 Pro., D 7 Ent., D 2010 Pro.
|
Verfasst: Di 19.11.19 11:13
Hallo,
ich hab eine kleines Problem, dass anscheinend eher ein Delphi-Bug zu sein scheint.
Ich hab ein Dataset-Field mit einer OnValidate Prüfung.
wenn ich den Button direkt anklicke, kommt die Exception und ich komme auch nicht weiter.
wenn ich Button.OnClick über TAction über einen ShortCut auslöse, kommt die Exception aber der Dialog schließt sich auch.
Hab ich einen Denkfehler oder ein Bug?
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75:
| unit Unit3;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DB, Grids, DBGrids, StdCtrls, DBClient, Mask, DBCtrls, ActnList;
type TForm3 = class(TForm) dataset: TClientDataSet; dbgrd: TDBGrid; ds: TDataSource; dbedtDate: TDBEdit; actlst: TActionList; actFertig: TAction; btnEinfuege: TButton; btnok: TButton; procedure FormCreate(Sender: TObject); procedure actFertigExecute(Sender: TObject); procedure btnEinfuegeClick(Sender: TObject); procedure btnokClick(Sender: TObject); private procedure DoValidate(Sender: TField); public end;
var Form3: TForm3;
implementation
uses DateUtils;
{$R *.dfm}
procedure TForm3.actFertigExecute(Sender: TObject); begin if (self.btnok.enabled) and (self.btnok.visible) then begin btnOK.setfocus; btnOKClick(nil); end; end;
procedure TForm3.btnEinfuegeClick(Sender: TObject); begin dataset.Append;
dataset.FieldByName('Field1').Value := 'Artikel ' + IntToStr(dataset.Recordcount + 1); dataset.FieldByName('Field2').Value := date; dataset.FieldByName('Field3').Value := FormatDatetime('dd.mm.yyyy hh-mm-ss-zzz', now); dataset.Post; end;
procedure TForm3.btnokClick(Sender: TObject); begin Modalresult := mrOk; end;
procedure TForm3.DoValidate(Sender: TField); begin if DaysBetween(date, sender.asDatetime) > 7 then raise Exception.Create('Zu alt'); end;
procedure TForm3.FormCreate(Sender: TObject); begin dataset.CreateDataSet; dataset.FieldByName('Field2').OnValidate := DoValidate; end;
end. |
Im Anhang eine keines Beispiel, damit es leichter nachzuvollziehen ist.
Danke im voraus.
Einloggen, um Attachments anzusehen!
_________________ Wer sichert ist feige!!
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Di 19.11.19 12:22
Das liegt daran, dass du in der Action mit dem Setzen des Fokus die Prüfung auslöst, die OnValidate-Exception dabei abgefangen und dann danach der btnOKClick durchgeführt wird. Deshalb wird dabei das ModalResult wirklich gesetzt und das Fenster geschlossen.
Drückst du auf den Knopf, tritt das Problem auch beim Fokuswechsel auf, aber durch den Fehler wird der Klick, sprich die Methode btnokClick, gar nicht mehr ausgeführt.
|
|
Fienix
Beiträge: 109
Win 2K, Win XP Pro, Win 7
D 5 Pro., D 7 Ent., D 2010 Pro.
|
Verfasst: Di 19.11.19 12:33
Die Exception wird doch nicht abgefangen!
Es wird eine Exception ausgelöst und das Programm läuft trotzdem normal weiter?
_________________ Wer sichert ist feige!!
|
|
jasocul
Beiträge: 6388
Erhaltene Danke: 146
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Di 19.11.19 12:38
Sebastian hat ja schon was zu dem Problem geschrieben.
OnValidate wird ausgelöst, wenn das Feld aktualisiert wird. Das passiert beim Speichern des Datensatzes oder wenn das Eingabefeld den Focus verlieren soll (nicht verliert). Das OnValidate sorgt dafür, dass der Fokus bleibt. Du setzt ihn aber manuell um und bekommst dein Problem.
Fienix hat folgendes geschrieben : |
Hab ich einen Denkfehler oder ein Bug?
|
Es liegt ein konzeptioneller Fehler vor.
Wenn du TAction nutzt, dann weise die Action auch dem Button zu (im Objektinspektor). Das OnClick des Button dann bitte löschen und den entsprechenden Source ins OnExecute der Action verschieben. Ansonsten weißt du irgendwann nicht mehr, was du wo machst.
Außerdem hat TAction auch ein OnUpdate. Damit kannst du z.B. steuern, ob der Button enabled ist.
Da das OnValidate nur in den oben genannten Situationen reagiert, habe ich mich schon lange davon verabschiedet, bzw. eigentlich nich genutzt. Den Aufwand den man dafür treiben muss, damit es an den richtigen Stellen auch reagiert, war mir zu umständlich.
Die Prüfung muss sowieso gemacht werden. In deinem Beispiel kann man die Prüfung einfach auf die Action für den Button verlagern. Wenn das Datum ungültig ist, setzt du den Fokus wieder auf das Eingabefeld, machst ein ShowMessage und setzt keinen ModalResult.
Vorteil: Du hast die volle Kontrolle an der gewünschten Stelle.
Nachteil: Bei vielen Feldern, die geprüft werden müssen, wird der Anwender erst gewarnt, wenn schon viele Felder ausgefüllt sind. Das ist aber durchaus eine übliche Vorgehensweise.
|
|
Fienix
Beiträge: 109
Win 2K, Win XP Pro, Win 7
D 5 Pro., D 7 Ent., D 2010 Pro.
|
Verfasst: Di 19.11.19 12:58
Das funktioniert aber noch weniger.
Wenn die Action dem Button zugewiesen wird, wird ja überhaupt nix mehr geprüft,
deswegen wird ja der Focus explizit auf den Button gesetzt, um die Exception auszulösen.
bei dem SetFocus wird die Exception ausgelöst, ist auch richtig, aber warum läuft das Programm weiter?
_________________ Wer sichert ist feige!!
|
|
Fienix
Beiträge: 109
Win 2K, Win XP Pro, Win 7
D 5 Pro., D 7 Ent., D 2010 Pro.
|
Verfasst: Di 19.11.19 13:57
grundsätzlich ist das Problem nicht bei der TAction.
sondern beim SetFocus , anscheinend wird hier die Exception abgefangen
hier tritt das gleiche Problem auf:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| procedure TForm3.btnCloseClick(Sender: TObject); begin if (self.btnok.enabled) and (self.btnok.visible) then begin btnOK.setfocus; btnOKClick(nil); end; end; |
_________________ Wer sichert ist feige!!
|
|
jasocul
Beiträge: 6388
Erhaltene Danke: 146
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Di 19.11.19 14:20
Fienix hat folgendes geschrieben : | Das funktioniert aber noch weniger. |
Weil du konzeptionell falsch damit arbeitest. Das hatte ich versucht oben zu erläutern. Man muss sich entscheiden, ob man TAction verwendet oder nicht. Aber wenn man es nutzt, muss man konsequent sein.
Fienix hat folgendes geschrieben : | Wenn die Action dem Button zugewiesen wird, wird ja überhaupt nix mehr geprüft, |
Richtig, aber wie schon geschrieben, ist dein Konzept nicht in Ordnung.
Fienix hat folgendes geschrieben : | deswegen wird ja der Focus explizit auf den Button gesetzt, um die Exception auszulösen. |
OnValidate prüft den Wert, wenn man das DataSet-Feld (nicht das Eingabefeld) verlässt oder ein Post macht. Das hat zu dem Zeitpunkt nichts mit der fokussierten Eingabe-Komponente zu tun. Daher macht dein SetFocus im Source einen Wechsel zum Button und dir geht die Kontrolle darüber verloren. Der Fokus-Wechsel durch Auswahl mit der Maus läuft etwas anders.
Fienix hat folgendes geschrieben : | bei dem SetFocus wird die Exception ausgelöst, ist auch richtig, aber warum läuft das Programm weiter? |
Weil der Fokus durch deinen Source verändert wird und nicht durch das Event.
Mit OnValidate hat man immer diese Probleme. Deswegen nutze ich es nicht und kontrolliere die Daten z.B. vor einem DataSet.Post.
Es gibt da so eine nettes Ereignis (BeforePost) beim DataSet. Das eignet sich in den meisten Fällen ganz gut. Alternativ kann man das auch in einer Action machen, bevor man das Post auslöst.
|
|
jaenicke
Beiträge: 19285
Erhaltene Danke: 1743
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Mi 20.11.19 07:18
|
|
Fienix
Beiträge: 109
Win 2K, Win XP Pro, Win 7
D 5 Pro., D 7 Ent., D 2010 Pro.
|
Verfasst: Mi 20.11.19 10:12
Ich habs jetzt soweit verstanden, denk ich.
Und das passende Event hab ich auch gefunden:
ds.dataset.UpdateRecord;
damit hab ich genau das richtige um den Ablauf nicht komplett überarbeiten zu müssen:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9:
| procedure TForm3.actFertigExecute(Sender: TObject); begin if (self.btnok.enabled) and (self.btnok.visible) then begin ds.dataset.UpdateRecord; btnOK.setfocus; btnOKClick(nil); end; end; |
Danke euch für die Hilfe!
_________________ Wer sichert ist feige!!
|
|
jasocul
Beiträge: 6388
Erhaltene Danke: 146
Windows 7 + Windows 10
Sydney Prof + CE
|
Verfasst: Mi 20.11.19 13:28
Gern geschehen.
Dennoch solltest du dein Konzept überdenken, wie du mit TAction arbeitest.
|
|
|