-1

在 Windows 10 中的 Delphi 11 32 位 VCL 应用程序中,在运行时,我在按住 SHIFT 和 CTRL 修饰键的同时右键单击控件,将单击的控件的名称复制到剪贴板:

procedure TformMain.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
begin
  case Msg.message of
    Winapi.Messages.WM_RBUTTONDOWN:
      begin
        // Detect the name of the clicked control:
        var ThisControl: Vcl.Controls.TWinControl;
        ThisControl := Vcl.Controls.FindControl(Msg.hwnd);
        if Assigned(ThisControl) then
        begin
          var keys: TKeyboardState;
          GetKeyboardState(keys);
          // when right-clicking a control, hold down the SHIFT and CTRL key to escape the possible default click behavior of the control:
          if (keys[VK_SHIFT] and $80 <> 0) and (keys[VK_CONTROL] and $80 <> 0) then
          begin
            Handled := True;
            //CodeSite.Send('TformMain.ApplicationEvents1Message: ThisControl.Name', ThisControl.Name);
            Vcl.Clipbrd.Clipboard.AsText := ThisControl.Name;
          end;
        end;
      end;
  end;
end;

这适用于几乎所有控件,除了TimageTLabel(可能还有一些其他控件类型)。我怎样才能使这个工作与TimageTLabel呢?

4

1 回答 1

3

TImage并且TLabel源自TGraphicControl,而不是TWinControl。他们没有HWND自己的,这就是为什么Vcl.Controls.FindControl()不适合他们。您正在接收WM_RBUTTONDOWN属于他们Parent的消息HWND。在内部,当 VCL 路由消息时,它将考虑图形子控件。但你的代码不是。

试试Vcl.Controls.FindDragTarget()吧。它将屏幕坐标作为输入(您可以通过使用 or 转换客户端坐标来获得WM_RBUTTONDOWNlParamWinapi.ClientToScreen()然后Winapi.MapWindowPoints()返回TControl这些坐标处的 ,因此它适用于窗口控件和图形控件。

话虽如此,您不需要Winapi.GetKeyboardState()在这种情况下使用,因为WM_RBUTTONDOWN'wParam告诉您在生成消息时是否按住键(请记住,您正在处理SHIFT排队消息,因此在生成消息的时间和您收到消息的时间)。CTRL

procedure TformMain.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean);
const
  WantedFlags = MK_SHIFT or MK_CONTROL;
begin
  if Msg.message = WM_RBUTTONDOWN then
  begin
    // Detect the name of the clicked control:
    var Pt: TPoint := SmallPointToPoint(TSmallPoint(Msg.LParam));
    Windows.ClientToScreen(Msg.hwnd, Pt);
    var ThisControl: TControl := FindDragTarget(Pt, True);
    if Assigned(ThisControl) then
    begin
      // when right-clicking a control, hold down the SHIFT and CTRL key to escape the possible default click behavior of the control:
      if (Msg.wParam and WantedFlags) = WantedFlags then
      begin
        Handled := True;
        //CodeSite.Send('TformMain.ApplicationEvents1Message: ThisControl.Name', ThisControl.Name);
        Clipboard.AsText := ThisControl.Name;
      end;
    end;
  end;
end;
于 2021-11-11T19:05:17.910 回答