I use Delphi xe-8 and I use thread for queries and I want to show an hourglass cursor while my thread is working.
I'm setting my cursor to hourglass but when I hover on controls on the form, for example over a grid, the cursor appears as the default; the cursor only changes when I hover over the form itself. What I want to do is to show an hourglass cursor over just the form and any controls on the form, but not the rest of the application.
I tried to set Screen.Cursor to crHourGlass but then it is for the whole application, so it is an hourglass even if I'm hovering on another form.
Is it possible to do that? If it is how can i do that?
When the mouse is over a given TWinControl
, the OS sends it a WM_SETCURSOR
message requesting it to set the onscreen cursor icon. The VCL's default processing of that message goes like this:
if the Screen.Cursor
is not crDefault
, that is the cursor used.
otherwise, if the TWinControl
has a TGraphicControl
child underneath the mouse, and its Cursor
is not crDefault
, that is the cursor used.
otherwise, if the TWinControl
's own Cursor
is not crDefault
, that is the cursor used.
otherwise, the message is passed to the parent window. Repeat steps 2-3.
So, to do what you are asking for, try setting the Form's Cursor
to the desired value, and make sure all child controls on the Form have their Cursor
set to crDefault
.
If that is not an option for you, or if it doesn't work, you can instead have your Form class override its virtual WndProc()
method (or use a message
method) to handle the WM_SETCURSOR
message directly. Call the inherited
handler first, and if the message's Result
is FALSE
and the worker thread is running then call the Win32 API SetCursor()
function to set your desired cursor icon, and set the message's Result
to TRUE
, eg:
protected
procedure WndProc(var Message: TMessage); override;
...
procedure TMyForm.WndProc(var Message: TMessage);
begin
inherited;
if (Message.Msg = WM_SETCURSOR) and (Message.Result = 0) and (Thread is Running) then
begin
Windows.SetCursor(Screen.Cursors[crHourGlass]);
Message.Result := 1;
end;
end;
Or
private
procedure WMSetCursor(var Message: TMessage); message WM_SETCURSOR;
...
procedure TMyForm.WMSetCursor(var Message: TMessage);
begin
inherited;
if (Message.Result = 0) and (Thread is Running) then
begin
Windows.SetCursor(Screen.Cursors[crHourGlass]);
Message.Result := 1;
end;
end;
This way, Screen.Cursor
and individual TControl.Cursor
properties still take priority, but if the cursor remains unchanged (ie, all of the properties are crDefault
) then you can change the cursor for the entire Form as a whole, without affecting other Forms.