Title: Override Global Screen.Cursor Change for a Cancel type Button is Delphi Applications
When you want to run a lengthy process in your application that needs no user interaction, you can change the value of the Screen.Cursor property to have the mouse cursor display as a hourglass, for example, while the process is being executed.
The Screen.Cursor property of the global Screen object has a global effect. It controls the cursor shape for all the forms, and the controls on the form, in the application.
When you change the global screen cursor, the user can still click any buttons on the form but visual appearance of the cursor does not imply so.
When you "surround" a consuming / critical operation with a global cursor change, you might want to have one button act as a cancel button, where the click to this button would stop the process.
Since the Screen.Cursor will affect all the controls on the form, you might want to make sure that this "cancel button" displays a "normal" cursor when the mouse pointer is over it.
Note that in the above scenario I'm not taking about the Cancel property of a Button which determines whether the button’s OnClick event handler executes when the Escape key is pressed.
I'm talking of a button that when clicked will stop the lengthy process.
Force Button.Cursor to "Override" Screen.Cursor
Screen.Cursor := crHourglass;
try
// Do some "lengthy operation"
//have a button, btnCancel that can stop this operation
finally
Screen.Cursor := crDefault;
end;
If the "lengthy operation" does not block message processing completely your "cancel" button will be clickable. To ensure messages are not blocked you can call Application.ProcessMessages in intervals, if the process is being executed in the main thread of the application.
While the lengthy process is being run your btnCancel will display a hourglass when the mouse cursor moves over it - since crHourglass is globally set by the Screen object.
If only for this button you want to display some other cursor shape, the one set using that button's Cursor property, you can hijack the Tag property of the button to set the cursor shape when the mouse enters its client area and set it back to global Screen value when the mouse exits its client area. Here's how:
//"cancel" button OnMouseEnter event handler
procedure TOperationForm.btnCancelMouseEnter(Sender: TObject) ;
begin
//store current screen.cursor value
btnCancel.Tag := Screen.Cursor;
//temporary set screen.cursor
Screen.Cursor := btnCancel.Cursor;
end;
//"cancel" button OnMouseLeave event handler
procedure TOperationForm.btnCancelMouseLeave(Sender: TObject) ;
begin
//restore current screen.cursor value
Screen.Cursor := btnCancel.Tag;
end;
The above code presumes you are not already using the Tag property of the cancel button to store some other data.
The OnMouseEnter event handler is used to store the current value of the global mouse shape in the Tag property of the button. Screen.Cursor is set to the value of the button's Cursor property.
The TCursor is defined as type TCursor = -32768..32767, and Tag is an integer property, you can safely store the value of Cursor to the Tag property.
When the mouse leaves the button, the Screen.Cursor is restored.
A neat trick. For a more global solution, you might want to create your own button and store the global cursor value in some integer type property.