Cursor handling in Firemonkey

  

Can anyone clarify how cursors in Delphi FMX 10.3.1 work? I have a lengthy action and I want the application’s cursor to be displayed as
crHourglass while the action is executing. In the following code I have introduced 3 options for setting the cursor to crHourglass.

procedure TFormMain.ActionFindExactMatchesExecute(Sender: TObject);
const
CCursorOption= 2;
var
IterationContextHits: TIterationContextHits;
begin
PanelResults.SendToBack;
PanelProgress.BringToFront;
case CCursorOption of
0: Self.Cursor:= crHourglass;
1: ButtonFindExactMatches.Cursor:= crHourglass;
2: CursorManager.SetCursor(crHourglass);
end;
{Create TIterationContextHits object to hold progress variables:}
IterationContextHits:= TIterationContextHits.Create;
try
{Lengthy code that searches multiple files for string matches}
{Report result of operation:}
ShowMessage(‘Number of matches found: ‘ + IntToStr(FHitCount));
{Update GUI:}
DataToControls;
PanelResults.BringToFront;
finally
IterationContextHits.Free;
case CCursorOption of
0: Self.Cursor:= crDefault;
1: ButtonFindExactMatches.Cursor:= crDefault;
2: CursorManager.RestorePrevCursor;
end;
end;
end;

In the first option, I set the Cursor property of the MainForm to crHourGlass in the expectation that during execution the
application will display the InheritedCursor property, which should search the component z-order stack all the
way back to the main form for the first component whose cursor value is not crDefault. But this does not work.

In the second option I set the cursor property of a button that is linked to the action. If the button is clicked to launch the action,
the cursor change works. But if the action is launched from a main menu item, then it doesn’t.

In the third option I use an object of class TCursorManager that I have written to wrap the platform-dependent service IFMXCursorService.
This mostly works, but not invariably. The code for this is:

TCursorRecord= record
FCursor: TCursor;
FStartTime: integer;
end;

TCursorRecordArray= array of TCursorRecord;

TCursorManager= class
private
FCursorService: IFMXCursorService;
FCursorRecordStack: TCursorRecordArray;
FCursorRecordCount: integer;
protected
function GetCursorTickCount: integer;
public
constructor Create;
destructor Destroy; override;
function GetCursor: TCursor;
{Returns currently set cursor}
procedure SetCursor(Cursor: TCursor);
{Sets new cursor}
function RestorePrevCursor: TCursor;
{Restores cursor previously set using this object}
property Cursor: TCursor read GetCursor write SetCursor;
property CursorTickCount: integer read GetCursorTickCount;
end;

implementation

constructor TCursorManager.Create;
var
CurrCursorRecord: TCursorRecord;
begin
{Create platform-dependent cursor service:}
if TPlatformServices.Current.SupportsPlatformService(IFMXCursorService) then
FCursorService:= TPlatformServices.Current.GetPlatformService(IFMXCursorService)
as IFMXCursorService;
{Create current cursor record:}
CurrCursorRecord.FCursor:= FCursorService.GetCursor;
CurrCursorRecord.FStartTime:= GetTickCount;
{Put current cursor record onto CursorRecordStack:}
SetLength(FCursorRecordStack, 8);
FCursorRecordCount:= 1;
FCursorRecordStack[0]:= CurrCursorRecord;
end;

function TCursorManager.RestorePrevCursor: TCursor;
var
PrevCursorRecord: TCursorRecord;
begin
if Assigned(FCursorService) then
begin
if FCursorRecordCount>0 then
begin
{Remove current cursor record from stack:}
FCursorRecordCount:= FCursorRecordCount – 1;
PrevCursorRecord:= FCursorRecordStack[FCursorRecordCount-1];
{Reduce size of stack array if possible:}
if FCursorRecordCount mod 8 = 0 then
SetLength(FCursorRecordStack, FCursorRecordCount);
{Update start time of new curr cursor:}
PrevCursorRecord.FStartTime:= GetTickCount;
{Set previous cursor in system:}
FCursorService.SetCursor(PrevCursorRecord.FCursor);
{Return prev cursor:}
Result:= PrevCursorRecord.FCursor;
end;
end;
end;

procedure TCursorManager.SetCursor(Cursor: TCursor);
var
NewCursorRecord: TCursorRecord;
begin
if Assigned(FCursorService) then
begin
{Set up new CursorRecord:}
NewCursorRecord.FCursor:= Cursor;
NewCursorRecord.FStartTime:= GetTickCount;
{Add new cursor record to stack:}
if FCursorRecordCount= Length(FCursorRecordStack) then
SetLength(FCursorRecordStack, FCursorRecordCount + 8);
Inc(FCursorRecordCount);
FCursorRecordStack[FCursorRecordCount-1]:= NewCursorRecord;
{Call system procedure to set cursor:}
FCursorService.SetCursor(Cursor);
end;
end;

What is the simplest way to achieve what I am seeking to accomplish?

Comments are closed.