光标在MouseDown上未更改

时间:2018-12-14 16:44:46

标签: delphi

我有一个包含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。 我在做什么错,我该如何解决?

3 个答案:

答案 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. WM_SETCURSOR message
  2. SetCapture function
  3. GetCapture function
  4. ReleaseCapture function

答案 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;