![]() |
Diverse Fokusprobleme
Die Suche hat etwas länger gedauert, vorallem da wir bisher dachten der Fehler liegt bei uns (irgendwelchen komischen Dingen in unserem Programm)
und es fiel nicht überall auf, da zufällig bei einigen selbstgebauten Dialogen der Fokus manuell gesetzt wurde. Das Problem lieg darin, daß öfters der Fokus einfach "verschwindet" und man erst manuell in das Edit/Grid wieder reinklicken muß. So, aber nun stellte sich raus, daß vermutlich seit den VISTA-Anpassungen, mit den neuen CommonControls, sich im Delphi ein liebevoller Bug versteckt, welcher grob fahrlässig den Fokus zerschießt. Und (vermutlich) wenn man einen Dialog im OnClose eines Fensters anzeigt, welches dann via caFree erst freigegeben wird, nachdem der Dialog sichtbar wurde, dann dreht alles durch und es passiert schonmal, das gleich die ganze Anwendung den Fokus verliert und im Hintergrund verschwindet. MDI-Fenster sind für Windows ja mehr Komponenten, als eigenständige "Fenster". Demo: - Fokus im Memo - links den Speedbutton anklicken und Dialog schließen => Fokus bleibt im Memo (siehe Text-Cursor oder einfach mal ein paar Buchstaben eingeben) - rechts den Speedbutton anklicken => Fokus ist weg (liegt jetzt auf der MainForm) - bei Fokus auf Button -> nach dem Dialog siehe gepünktelter Fokusrahmen oder einfach mal auf die Leertaste drücken - Beim Drücken auf einen Button, dann sollte nachher der Fokus beim Button liegen Grund: Irgendein Trottel Jemand war so schlau, liest vor dem ShowModal das das "für Windows" aktive Fenster aus und gibt ihm nach dem Dialog den Fokus. Leider ist hier aber nicht die MainForm aktiv, sondern das MDI-Child. Lösung, bis der Fehler nie repariert wird (da XE garantiert kein Update mehr bekommt): Screen.ActiveControl vorher auslesen und nachher ihm den Fokus zurückgeben. Oder besser noch nachher
Delphi-Quellcode:
(vorher muß man sich nichts speichern), denn die VCL denkt ja immernoch, daß der Fokus wo ganz anders liegt, nämlich dort, wo er auch sein sollte. :stupid:
SetFocus(AciveControl.Handle);
[edit] Neuer Anhang siehe #5 |
AW: Fokusproblem (MDI)
Und nun auch noch der nächste Schrott: (grade nochmal mit XE6 getestet und seit mindestens XE im Arsch)
TCommonDialog.Execute sucht sich zwar das "richtige" Fenster raus, wo der Dialog drangehängt werden soll (siehe ModalPopupMode), es sei denn man gibt dem Execute das gewünschte Fenster-Handle mit, aber beim TFindDialog.Execute wird letztendlich das ParentWnd dann doch nicht ausgewertet, stattdessen geht man bescheuerter Weise im TFindDialog.Execute auf EnumThreadWindows und holt sich dort die erste Form, welche gefunden wird (das zuletzt Erstellte), statt den Parameter zu verwenden. :wall:
Und hier auch mal ein Zweizeiler, welcher den Schrott demonstiert.
Delphi-Quellcode:
TMyForm.Create(Self).Close; // DFM: Visible=True
FindDialog1.Execute; procedure TForm1.Button1Click(Sender: TObject); begin with TForm.Create(Self) do begin Show; Close; end; FindDialog1.Execute; end; Standardmäßig hängen sich alle weiteren nichtmodalen Forms und die Dialoge an die MainForm und sind auch an Dieser ausgerichtet (stehen immer vor ihr). Wer das nicht will, muß nur ein bissl was machen: Application.ModalPopupMode sollte man, vorallem bei Mehrfensteranwendungen besser nicht auf dem Standardwert pmNone stehen lassen und bei den eigenen Forms, welche nicht von der MainForm aus gestartet werden, die aber nicht an/über der akiven Form hängen sollen ... da sollte man auch noch Form.PopupMode setzen. Hier wäre es einfacher, wenn man dem TForm.Show, ebenso wie schon beim Dialog.Execute (falls man den Wert nicht ignoriert), einen optionalen Parameter mitgeben könnte, wo man eine explizize Popupform übergibt, damit man das dort hat, wo man es auch braucht. Gerate nochmal getestet: Delphi 7 = OK / XE und XE6 = futsch Wer bezahlt uns eigentlich die versenkte Arbeitszeit? Wir dachten ja meistens, daß es an unserem Programm liegt, weil es ja sonst scheinbar funktioniert, da sich keiner beschwert. (da gingen inzwischen bestimmt schon mehrere Mann-Wochen drauf, in den letzten knapp 3 Jahren) Und es dauert bestimmt noch paar Stündchen, bis ich alle Delphi-Bugs erfasst hab (jetzt, wo ich endlich weiß, wo man suchen muß) und dann dürfen die sich über 'nen Anruf vom Cheffe freuen. [edit] Neuer Anhang siehe #5 |
AW: Fokusproblem (MDI)
Kannst Du Deinen Beitrag noch etwas raffen? Zwischen all dem Geschimpfe gehen die (vermutlich) guten Lösungen hoffnungslos unter.
|
AW: Fokusproblem (MDI)
Einen bekannten Fehler bin ich grade noch am Suchen, der sich bei den Kunden auch nett auswirkt ... danach würde ich die Fehler dann nochmal zusammengefassen.
Das mit dem Suchen-dialog fällt uns seit knapp einem halben jahr auf die Füsse, wobei wir nie rausfanden, warum es in manchen Fenstern ging und in Anderen nicht. Es war auch bisher nie Zeit da jetzt tagelang zu suchen, bis ich am Donnerstag mal wieder Zeit hatte und dann zufällg drüber gestolpert bin. Seit der Umstellung von D7 auf XE suche ich jetzt derartige Fehler und das ist auch einer der Hauptgründe, warum wir da immernoch auf XE festhängen, weil wir uns nicht trauten das komplette und jahrzehnte alte Projekt weiter hochzuportieren (wer weiß was dann zusätzlich auch nicht läuft). |
AW: Diverse Fokusprobleme
Liste der Anhänge anzeigen (Anzahl: 1)
falscher Fokus von Delphi gemerkt und gesetzt, bei neuen Common-Dialogen
Demo: Fokus ins Memo -> SpeedButton: New CommonDialog -> OK -> Fokus landet beim MDI-Parent (egal ob mit externem Fenster "New Form" oder nicht) Fokus falsch von Delphi gesetzt, bei Dialogen
Stattdessen wird in TFindDialog.Execute(ParentWnd) über EnumThreadWindows "irgendein" zuletzt erstelltes Fenster genommen, welches auch unsichtbar oder deaktivert sein kann. (wird garnicht geprüft) Demo 1: New Form -> FindText -> Abbrechen -> Fokus bei falscher Form Demo 2: New Form -> pmAuto1 schließen -> FindText -> Abbrechen -> Fokus ist komplett weg Zerstörung der PopupParent-Beziehung beim Schließen einer eingebetteten Form
Fokus-Setzten beim Schließen von Fenstern -> Fokus darf nicht umgesetzt werden, wenn er manuell wo anders hingelegt wurde
Demo 1: New Form -> New Form -> Fokus auf MainForm/MDIForm -> pmAuto1 oder pmAuto2 schließen -> Fokus bei der anderen pmAuto* und nicht in der MainForm Demo 2: New Form -> New Form -> New Form -> Fokus auf irgendein pmAuto* -> ein anderes pmAuto* schließen -> Fokus ist beim richtigen Fenster __________________________________________________ ____________________________________________ Sobald das Zielfenster nicht sichtbar ist, und es wird dennoch versucht den Fokus da hinzusetzen, dann verliert das Programm den Focus. Das wird halt über Windows.SetFocus gemacht, ohne den Rückgabewert auszuwerten, und nicht über TControl.SetFocus. (TControl.SetFocus wirft ja eine Exception wenn das Fenster/Control nicht fokusierbar ist) Wenn beim Fokuszurücksetzen seitens Delphi etwas total schief lief und dadurch das Programm im Hintergrund verschwindet, dann ist oftmals Screen.ActiveForm/Screen.ActiveCustomForm = nil. Selbst wenn das Programm absichtlich im Hintergrund landet, da ein anderes Programm den Fokus bekommt, dann gibt es eigentlich nie ein nil dort. Derartige Fehler konnten wir "beheben", indem ein Timer regelmäßig auf dieses nil prüft und dann das Programm wieder vor holt.
|
AW: Fokusproblem (MDI)
Statt dem Timer wäre auch
Delphi-Quellcode:
möglich (find ich in dem Zusammenhang sogar besser)
TApplicationEvents.OnIdle
|
AW: Diverse Fokusprobleme
OK, OnIdle wäre vielleicht auch gegangen.
Es wurde aber absichtlich ein Timer, damit ich ein zeitlich einheitliches und nachvollziehbares Verhalten hinbekomm. Welcher aktuell mit einem 100ms-Intervall nach je 10 Durchläufen den Status prüft, also alle 1 Sekunde. Wenn das Programm hängt (z.B. irgendwas Laden oder eine SQL-Abfrage), dann verlängert sich das Intervall entsprechend und löst nicht sofort nach dem Hängen aus. Das verhinderte recht zuverlässig, daß der Code auch auslöst, wenn dieses wirklich mal kurzzeitig nil ist (z.B. beim Wechsel von Fenstern), aber kurz danach von "alleine" wieder in einen korrekten Zustand gerät, womit mein Reparaturcode sonst den "korrekten" Fokus überschreiben würde. Und im Grunde war es nur ein "kurzfristiger" Bugfix (seit vielleicht 2 Jahren), bis die Fehler behoben sind. :stupid: |
AW: Diverse Fokusprobleme
Ich kenne das Problem auch schon lange bei TFindDialog. Zum Beispiel in anderen Forms als in der Mainform. Ich habe dafür folgenden Workaround in Application on Message:
Code:
Dann werden die Fenster wieder in der richtigen Reihenfolge und der FindDialog verschwindet nicht und ist focussiert
procedure TfmGeMail.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
var Shift: TShiftState; Key: Word; procedure GetShiftState(var Shift: TShiftState); var KeyboardState: TKeyboardState; begin Shift := []; GetKeyboardState(KeyboardState); if (KeyboardState[vk_Shift] and 128 = 128) then Shift := Shift + [ssShift]; if (KeyboardState[VK_CONTROL] and 128 = 128) then Shift := Shift + [ssCtrl]; if (KeyboardState[vk_Menu] and 128 = 128) then Shift := Shift + [ssAlt]; end; begin GetShiftState(Shift); Key := Msg.WParam; case Msg.Message of WM_KEYDOWN: case Key of Ord('F'): if (Shift=[ssCtrl]) then begin SetWindowPos (Application.handle,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE+SWP_NOSIZE or SWP_NOREDRAW); SetWindowPos(Application.Handle, HWND_NOTOPMOST, 0,0,0,0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOREDRAW ); end; ... |
AW: Diverse Fokusprobleme
Den TopMost-Schrott haben wir das letzte halbe/ganze Jahr über wieder komplett ausgebaut, da es mehr Probleme machte, als es löste.
Vorallem da dann ständig immer wieder mit Application.NormalizeTopMosts und Co. rumgepfuscht werden muß, wenn man einen Dialog/Fehlermeldung anzeigen will, damit die nicht hinter TopMost-Fenstern verschwinden. Eigentlich lässt sich das inzwischen besser über den PopupMode regeln (wenn es denn auch überall korrekt verwendet würde). Und bei Application.Handle musst du auch aufpassen, denn das "versteckte" Application-Message-Window wird von Delphis nicht mehr für die Anzeige verwendet, seitdem Delphi sich kompatibler zu Vista+ verhällt. Den in alten Delphis funktioniert z.B. das Aero-Preview nicht, da man in der Taskleiste nur das "leere" Application-Fenster sieht und nicht die MainForm. siehe Application.MainFormOnTaskBar |
AW: Diverse Fokusprobleme
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:52 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 by Thomas Breitkreuz