SetFocus versus WM_NEXTDLGCTL

Die meisten Entwickler verwenden SetFocus um in einem Dialog gezielt den Eingabefokus zu versetzen. Aber es gibt ein Problem, dem SetFocus nicht gerecht wird: der Default Button.
Der Default Button wird durch WM_SETDEFID bzw. CDialog::SetDefID gesetzt. SetFocus berücksicht das interne Konzept des Default Buttons nicht.

Wenn man mit der Tab-Taste durch einen Dialog springt und einen Button erwischt, dann wird dieser automatisch zum Default Button. Normalerweise ist das der OK-Schalter, er verliert dann den dicken Rahmen. Drückt man die Eingabe-Taste, dann wird nun der neue Schalter ausgelöst und nicht der OK-Schalter.
Landet der Fokus von einem Button dann bei einem Edit Control, dann wird der OK-Schalter wieder der Default Button und man kann mit der Eingabe-Taste den Dialog beenden.

Wenn nun SetFocus verwendet wird durch eine interne Funktion, dann wird dieser Mechanismus des Dialoges umgangen. Der Default-Button wird evtl. nicht korrekt gesetzt. Es kann sogar soweit kommen, dass es zwei Default-Schalter oder gar keinen mehr gibt. SetFocus führt immer zu Problemen wenn das neue Control oder das bisherige Control, welches den Fokus hatte, ein Button ist. Nur wenn beide Controls keine Button sind kann SetFocus gefahrlos verwendet werden.

Korrekt funktioniert das Ganze nur, wenn statt SetFocus, WM_NEXTDLGCTL verwendet wird, oder die entsprechenden MFC Funktionen, CDialog::NextDlgCtrl bzw. CDialog::GotoDlgCtrl verwendet werden.
Die Nachricht WM_NEXTDLGCTL wird auch intern durch die DefDialogProc behandelt und normalerweise durch IsDialogMessage erzeugt.
Gefahrlos ist auch die Verwendung von SetFocus in WM_INITDIALOG bzw. CDialog::OnInitDialog Handlern, die dann normalerweise mit FALSE, verlassen werden. Nach dieser Funktion sorgt der Dialog Handler, für die korrekte Behandlung der Default Buttons.

Fazit: Man sollte also innerhalb von Dialogen ganz auf SetFocus verzichten sondern nur WM_NEXTDLGCTL  bzw.  CDialog::NextDlgCtrl und CDialog::GotoDlgCtrl verwenden. Konsequenterweise sollte man dann auch in OnInitDialog Handlern auf SetFocus verzichten. ❗

4 Gedanken zu „SetFocus versus WM_NEXTDLGCTL“

  1. Ich habe ein Problem derart, daß in einer CFormView (dort gibt’s leider kein NextDlgCtrl/GotoDlgCtrl) ein Setfocus für ein OLE-DtPicker-Control
    nicht funktioniert, wenn das SetFocus aus einem TAB-Key-Event-Handler heraus aufgerufen wird;
    für alle „normalen“ Controls (Edit/Button) tut es, aber für den DTPicker nicht.
    Focus-Setzen mit Post/Send-Message funktioniert auch nicht.

    Das Problem existiert aber nur ab VS2003/MFC70 (auch in VS2005/MFC80 und VS2008/MFC90); mit VC6/MFC42 funktioniert alles
    (mit SetFocus) wie gewünscht.

    Haben Sie eine Idee, was man da noch versuchen könnte ?

  2. Vielen Dank für den Tipp; damit funktioniert es auch mit VS2008/MFC90 hervorragend !

    (Es war mir nicht klar, daß das nur Wrapper für Messages sind und daß die Messages dann nicht nur für „normale“ Dialoge, sondern auch für CFormView funktionieren).

  3. Das funktioniert sogar mit VC6.
    Es lohnt immer mal einen Blick auf die Funktion in der MFC selbst zu werfen! Man lernt immens viel. 😉

    Zudem sollte Dir auch klar sein, dass ein CFormView intern einen ganz normalen nicht modalen Standard Dialog anlegt.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

I accept that my given data and my IP address is sent to a server in the USA only for the purpose of spam prevention through the Akismet program.More information on Akismet and GDPR.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.