FindDragTarget 不检测禁用的控件

FindDragTarget does not detect disabled controls

创建一个 Delphi VCL 表单应用程序并在表单上放置 2 TButton 和一个 TApplicationEvents:

然后插入这些事件处理程序:

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.AppEvnts;

type
  TForm2 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    ApplicationEvents1: TApplicationEvents;
    procedure ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
begin
  Screen.Cursor := crHelp;
end;

procedure TForm2.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
var
  Target: TControl;
  Point: TPoint;
begin
  if Msg.Message = WM_LBUTTONDOWN then
  begin
    if Screen.Cursor = crHelp then
    begin
      Screen.Cursor := crDefault;
      Handled := True;
      GetCursorPos(Point);
      Target := FindDragTarget(Point, True);
      if Assigned(Target) then
        ShowMessage(Target.Name)
      else
        ShowMessage(IntToStr(Point.X) + ', ' + IntToStr(Point.Y));
    end;
  end;
end;

end.

现在单击 Button1 将鼠标指针更改为 crHelp

然后再次单击 Button1,它会正确显示名称 "Button1"。

现在再次单击 Button1 将鼠标指针再次更改为 crHelp

然后点击禁用的Button2: 你可以看到现在FindDragTarget没有检测到禁用的控件,虽然参数AllowDisabled设置为True.

那么如何通过单击鼠标来检测禁用的控件?

Delphi 10.1.2

"problem"(这实际上是设计使然)是FindDragTarget函数不检查禁用子Windowed控件。

function FindDragTarget(const Pos: TPoint; AllowDisabled: Boolean): TControl;
var
  Window: TWinControl;
  Control: TControl;
begin
  ...
  Control := Window.ControlAtPos(Window.ScreenToClient(Pos), AllowDisabled);
  ...
end;

请注意,Window.ControlAtPos 仅传递 AllowDisabled 参数,而不传递 AllowWinControls(默认情况下为 False)。

FindDragTarget 只会找到子 TGraphicControl 后代控件(使用其父句柄)。

您可以改用这个函数:

function FindDragTargetEx(const Pos: TPoint; AllowDisabled: Boolean; AllowWinControls: Boolean): TControl;
var
  Window: TWinControl;
  Control: TControl;
begin
  Result := nil;
  Window := FindVCLWindow(Pos);
  if Window <> nil then
  begin
    Result := Window;
    Control := Window.ControlAtPos(Window.ScreenToClient(Pos), AllowDisabled, AllowWinControls);
    if Control <> nil then Result := Control;
  end;
end;