Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Restore last focus (https://www.delphipraxis.net/114234-restore-last-focus.html)

taaktaak 21. Mai 2008 22:42


Restore last focus
 
Moin, Moin,
normalerweise ist es wohl uninteressant, welches Control zuletzt den Focus hatte. Für mich gibt es da aber eine Ausnahme: Rufe ich in meinem Programm mit einem Button die Hilfe auf, möchte ich nach Schliessen des Hilfefensters den Focus wieder auf dem zuletzt benutzten Control haben - und nicht auf dem Help-Button. Bisher habe ich das immer recht aufwendig in jedem relevanten Formular lokal programmiert. Blöde Lösung! Heute Abend hatte ich dann eine Idee, die ich dann in folgender Mini-Klasse umgesetzt habe:

Delphi-Quellcode:
unit rzM_WatchFocus;

interface { ----------------------------------------------------------------- }

uses Wintypes,Classes,Controls,Forms;

type TWatchFocus = class(TComponent)

                    private

                     FActControl,
                     FLastControl                : TWinControl;
                     procedure  SaveFocus       (Sender:TObject);

                    public

                     procedure  RestoreFocus;
                     constructor Create          (AOwner:TComponent); override;
                     destructor Destroy;                             override;

                    end;

var WatchFocus  : TWatchFocus;

implementation { ------------------------------------------------------------ }

procedure TWatchFocus.SaveFocus(Sender:TObject);
begin
  if FActControl=nil then FActControl:=Screen.ActiveControl
                     else begin FLastControl:=FActControl;
                                FActControl :=Screen.ActiveControl
                                end
end;

procedure TWatchFocus.RestoreFocus;
begin
  if FLastControl<>nil then FLastControl.SetFocus
end;

constructor TWatchFocus.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  FActControl :=nil;
  FLastControl:=nil;
  Screen.OnActiveControlChange:=SaveFocus
end;

destructor TWatchFocus.Destroy;
begin
  Screen.OnActiveControlChange:=nil;
  inherited Destroy
end;

initialization { ------------------------------------------------------------ }

  WatchFocus:=TWatchFocus.Create(nil);

finalization { -------------------------------------------------------------- }

  WatchFocus.Free;
  WatchFocus:=nil;

end.
Die Anwendung ist denkbar einfach; die Klasse wird lediglich per USES eingebunden. Damit steht dann die Prozedur "RestoreFocus" zur Verfügung. Anwendungsbeispiel:

Delphi-Quellcode:
procedure TfoConfig.buHelpClick(Sender:TObject);
begin
  case PageControl.ActivePageIndex of
    0 : Application.HelpJump('ConfigStartup');
    1 : Application.HelpJump('ConfigColorAlphablend');
    end;

  WatchFocus.RestoreFocus // << Focus wieder auf letztes Control vor HelpButton setzen
end;
Bislang funktioniert das wie gewünscht. Habe ich da mal wieder zu aufwendig gedacht, da Delphi diese Funktionalität schon bietet und ich das nur nicht gefunden habe?

PS:
Kann mir bitte mal einer erklären, wieso TWatchFocus.Create(nil) mit NIL erfolgen muss (hatte erst Self probiert, funktionierte aber nicht)

SirThornberry 21. Mai 2008 22:59

Re: Restore last focus
 
Zitat:

Kann mir bitte mal einer erklären, wieso TWatchFocus.Create(nil) mit NIL erfolgen muss (hatte erst Self probiert, funktionierte aber nicht)
Es muss nicht nil sein sondern einfach nur vom Typ TComponent. Und Self steht nunmal nur innerhalb einer Klasse zur verfügung weil es auf die aktuelle Instanz zeigt.

An sich ist das ganze eine ganz nette Idee aber ein paar Kritikpunkte/Verbessungspunkte hab ich.

Was mir an deiner Klasse nicht gefällt ist das sie das Screen.OnActiveControlChange nutzt. Wenn dieses Event bereits in Verwendung ist wird es einfach umgesetzt was nicht sonderlich schön ist. Wenn es unbedingt das Event sein soll wäre es schön wenn du prüfst ob bereits eine Methode zugewiesen ist und diese dann gegebenfalls von deinem Event aus aufrufst. Beim Zerstören dann natürlich auch schauen ob dem Event noch deine Methode zugewiesen ist und nur dann das Event auch wieder zurück setzen.

Wenn die Komponente universell nutzbar sein soll wäre es auch schön wenn du eine History führst die nicht nur das letzte Control kennt sondern einige zuvor auch noch.
Zusetzlich solltest du auch sicherstellen das dieses Control (fLastControl) auch noch existiert und nicht in der Zwischenzeit frei gegeben wurde. Dann würde dein fLastControl ins Nirvana zeigen und es kracht.

Aber wie bereits erwähnt, die Idee an sich ist nicht schlecht.

taaktaak 21. Mai 2008 23:18

Re: Restore last focus
 
Moin, Moin,
vielen Dank für die Anmerkungen, werde das kurzfristig (versuchen) einzubauen. Es kracht leider auch noch an anderer Stelle, wie ich eben (wie immer so kurz vor dem Aussschalten des PC) feststellen musste: Nach einem Fensterwechsel wird gemeckert "Ein deaktiviertes oder unsichtbares Fenster kann nicht den Fokus erhalten" - Na, da muss doch noch einmal gefeilt werden...

angefügter Beitrag:
Moin, Moin,
die Verwendung von Screen.OnActiveControlChange ist wohl tatsächlich der falsche Ansatz! Klasse und Anwendungsprogramm können sich gegenseitig die Events "klauen". In der Klasse könnte man das noch abfangen, aber wenn das auch im Anwendungsprogramm erfolgen muss, ist die Bequemlichkeit wieder futsch!
Habe jetzt 'ne Weile den direkten Ansatz (also Windows-Messages) ohne wirkliche Ergebnisse versucht, muss aber aus Zeitmangel dieses Thema erst einmal abbrechen.
Für die angesprochene Fokus-Historie könnte man vielleicht einen Ringpuffer verwenden. Aber, wie gesagt, muss auf später verschoben werden.
:(

[edit=SirThornberry]Beiträge zusammengeführt - Mfg, SirThornberry[/edit]


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:25 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz