The TdnFocusTracker is a component that keeps track of the the focus changes on a form and exposes what control had last focus before the focus shifted to the current ActiveControl. It also exposes what keyboard key was last pressed and what the keyboard state was. Additionaly it offers a TNotifyEvent which gets triggered everytime a focus change occurs.
Following is an example how to use it:
Add the unit to the {interface} uses clause:
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
udnFocusTracker;
Add a field of type TdnFocusTracker in your form's private section:
TForm1 = class(TForm)
private
{ private declarations }
myFocusTracker : TdnFocusTracker;
.
.
.
Create the component in the Form's OnCreate handler:
procedure TForm1.FormCreate(Sender:TObject);
begin
myFocusTracker := TdnFocusTracker.Create(self);
.
.
.
If your code is chaotic, or you place the TdnFocusTracker creation call in a reoccuring event handler, you can always check if the form has already a focus tracker component and obtain it, before trying to create it, like this:
myFocusTracker := TdnFocusTracker.FindTrackerOnForm(self);
if not assigned(myFocusTracker)
then myFocusTracker := TdnFocusTracker.Create(self);
The FindTrackerOnForm is a class method, it accepts a TCustomForm parameter and returns nil if no tracker exists on the form or a pointer to the tracker.
The tracker offers a Notification event you can hook into to get notified whenever a focus change occurs. To set this up you have to have a TNotifyEvent method and assign it like bellow:
myFocusTracker.NotifyOnFocusChanged := @CentralFocusChangeHandler;
This is completely optional, the focus changes and last key and shift states will be tracked regardless of if you use this notification.
Once you have created all controls (if you create any by code) you should invoke the method to start tracking:
myFocusTracker.ComposeTrackingList;
This will cause the tracker to create an internal list of objects, each of those pointing to a control on the form and placing code to intercept the commands that are send to each control.
At any time after tracking has started you can obtain the values for which control was last active before the focus shifted to the current ActiveControl, what key was last pressed (vk code that reflects LCLType.VK_XXX values) and the shiftstate. Those are Exposed by the properties LastActiveControl, LastKeyPressed and LastShiftState respecively. Key and ShiftState values are same as those passed to the standard OnKeyDown, OnKeyPress and OnKeyUp event handlers, except here they are read-only.
There is no need to destroy/free the focus tracker, it will be freed by the form when the form is destroyed.
NOTES and LIMITATIONS:
i.
The TdnFocusTracker needs an existing TCustomForm as its owner passed as parameter to its constructor. An invalid or unassigned (nil) form parameter will fail the component construction raising an exception with following message:
TdnFocusTracker needs an existing owner of type TCustomForm
ii.
Only 1 TdnFocusTracker per Form allowed, subsequent creation attempts will fail the component construction raising an exception with following message:
Only 1 TdnFocusTracker per form required and allowed
iii.
Focus tracking will start once you call ComposeTrackingList. Subsequent calls to this method will clear and reconstruct the internal tracking list and restart tracking.
iv.
When using the focus change notification event make sure to avoid focus changes from within it. It will not fall into an endless loop but you will not get subsequent focus change notification triggered while in this handler.
Also make sure to catch and handle any exceptions your code may produce.
v.
If a mouse click resulted in a focus change then the LastKeyPressed will be equal to LCLType.VK_LBUTTON.
vi.
If only 1 control has ever been active on the form then LastActiveControl will equal nil.
vii.
The property TrackedControlCount returns the number of currently tracked controls. If this number is less than 1 then either your form has no controls on it or you have not called ComposeTrackingList yet.
- - - - - - - - -
EDIT.:
viii.
Another important limitation: Controls created after ComposeTrackingList will not be tracked.
If for example you have a tStringGrid with editing enabled, the cell's implace-editor is created and destroyed as needed. That editor would not have existed at the time of the tracking list creation and so will not produce tracking results.
- - - - - - -
Best regards