我有一个包含2个事件的TPanel:
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;
当我单击面板(MouseDown事件)时,光标不会更改为crSizeAll
。
我在做什么错,我该如何解决?
答案 0 :(得分:7)
您没事。捕获鼠标输入只是一个简单技巧。在TPanel
上按下鼠标左键(LMB)后,此面板将退出鼠标。
此后,您的代码Panel1.Cursor := crSizeAll;
开始运行。如您在VCL的源中所见,TControl
向自身发送消息CM_CURSORCHANGED
来设置所需的游标类型。由于TWinControl
基于TControl
,因此它会处理此消息并检查是否捕获了鼠标输入。如果不是这样,则TWinControl
向自身发送消息WM_SETCURSOR
以便设置新的光标。
但是Microsoft明确指出,消息WM_SETCURSOR
有一些限制:
如果鼠标使光标在窗口内移动并且未捕获鼠标输入,则发送到窗口。
因此,如果已捕获鼠标输入,则无法更改光标的类型。您可以做的一件事是打电话给ReleaseCapture
:
procedure TForm1.Panel1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
ReleaseCapture;
Panel1.Cursor := crSizeAll;
end;
但是我不建议这样做,因为它破坏了鼠标输入的范式(我认为,一旦按下LMB,则应保持按下状态,直到由于重要原因(例如单击按钮)释放为止,但是您可以自行决定如何使用ReleaseCapture
)。
重要!
用户 Zig 执行的测试证明,使用ReleaseCapture
方法是不合适的,因为如果鼠标光标移到OnMouseUp
之外且LMB已释放,则该方法将禁止生成TPanel
事件
有用的信息:
答案 1 :(得分:6)
Dima解释了为什么更改Panel1.Cursor
并没有达到您想要的效果。
或者,您也可以更改Screen.Cursor
:
procedure TForm1.Panel1MouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Screen.Cursor := crSizeAll;
end;
procedure TForm1.Panel1MouseUp(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
Screen.Cursor := crDefault;
end;
答案 2 :(得分:6)
作为Dima explained,面板的Cursor
设置没有生效的原因是,该面板无法处理WM_SETCURSOR
消息,因为只要捕获鼠标,就捕获了鼠标按钮。
要立即设置光标,可以使用SetCursor
API。可能的不利影响是,光标将保持您设置的状态,直到释放鼠标按钮为止,即使在面板外部也是如此。
procedure TForm1.Panel1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
SetCursor(Screen.Cursors[crSizeAll]);
end;
您无需重置光标,因为在释放鼠标按钮后,将采用默认设置(响应WM_SETCURSOR
消息)。
如果希望光标在面板外回复并在再次进入面板时再次设置,则可以包含OnMouseMove
事件处理程序。这是因为自从鼠标捕获到鼠标以来,即使鼠标在面板之外,鼠标消息也将被定向到面板:
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;