I have a TPanel with 2 events:
procedure TForm1.Panel1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Panel1.Cursor := crSizeAll;
end;
procedure TForm1.Panel1MouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Panel1.Cursor := crDefault;
end;
When I click on the panel (MouseDown event) the cursor does not change to crSizeAll
.
What am I doing wrong and how can I resolve this?
You did all right. There is just a simple trick with capturing the mouse input. Once you've pressed Left Mouse Button (LMB) on TPanel
this panel has got mouse unput.
After that happened, your code Panel1.Cursor := crSizeAll;
is beginning to run. As you can see in the sources of VCL, TControl
sends message CM_CURSORCHANGED
to itself to set needed type of cursor. Since TWinControl
is based on TControl
, it handles this message and checks if mouse input has been captured. If this is not so, then TWinControl
sends message WM_SETCURSOR
to itself in order to set new cursor.
But Microsoft clearly stated that message WM_SETCURSOR
has a little restriction:
Sent to a window if the mouse causes the cursor to move within a window and mouse input is not captured.
So, there is no way to change cursor's type if mouse input has been captured. One thing you could do is to call ReleaseCapture
:
procedure TForm1.Panel1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
ReleaseCapture;
Panel1.Cursor := crSizeAll;
end;
But I wouldn't recommend do it this way since it breaks the paradigm of mouse input (in my opinion, once LMB was pressed, then it should stay pressed until it released by important reason (f.e. click on button), but you are free to decide how to use ReleaseCapture
on your own).
Important!
Test executed by user Zig proved that using ReleaseCapture
method is not appropriate since it forbids generating OnMouseUp
event if mouse cursor gone outside of TPanel
and LMB has been released.
Useful information:
As Dima explained the reason the Cursor
setting of the panel does not have an effect is that, the panel cannot process WM_SETCURSOR
messages since the mouse is captured as long as the mouse button is pressed.
To set the cursor immediately, you can use the SetCursor
API. The possible downside is that the cursor will remain what you set until you release the mouse button, even outside the panel.
procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
SetCursor(Screen.Cursors[crSizeAll]);
end;
You don't need to reset the cursor since the default will be assumed (in response to WM_SETCURSOR
messages) after the mouse button is released.
If you want the cursor to revert outside of the panel and set again when it enters on the panel again, you can include an OnMouseMove
event handler. That's because mouse messages will be directed to the panel even when outside the panel since it captured the mouse:
procedure TForm1.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
begin
if Mouse.Capture = Panel1.Handle then begin
if PtInRect(Rect(0, 0, Panel1.Width, Panel1.Height), Point(X, Y)) then
SetCursor(Screen.Cursors[crSizeAll])
else
SetCursor(Screen.Cursors[crDefault])
end;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With