Delphi 用鼠标点击任何VCL组件,并确定其.Tag值

Delphi 用鼠标点击任何VCL组件,并确定其.Tag值,delphi,Delphi,我正在使用一个国产的翻译工具。(下次我将使用其中一个库,如下所述:) 我的翻译人员抱怨说,翻译一长串字符串很困难,因为他们没有在上下文中看到它们(在它们出现的屏幕上) 一位翻译提出了一个很好的建议,他应该能够点击一个组件来改变它的文本。如果我能找到一种方法在程序范围内钩住一个事件,这样当用户在按住CTRL键的同时单击一个组件时,就会调用一个事件处理程序,那么我就可以实现这个。事件处理程序将确定组件是否具有.Caption属性,如果是,则获取标记组件的值(然后允许一些用户输入) (每个可翻译组件的

我正在使用一个国产的翻译工具。(下次我将使用其中一个库,如下所述:)

我的翻译人员抱怨说,翻译一长串字符串很困难,因为他们没有在上下文中看到它们(在它们出现的屏幕上)

一位翻译提出了一个很好的建议,他应该能够点击一个组件来改变它的文本。如果我能找到一种方法在程序范围内钩住一个事件,这样当用户在按住CTRL键的同时单击一个组件时,就会调用一个事件处理程序,那么我就可以实现这个。事件处理程序将确定组件是否具有.Caption属性,如果是,则获取标记组件的值(然后允许一些用户输入)

(每个可翻译组件的标记中都有唯一的整数,我用它来查找组件的.Caption。)

有什么关于如何进行的建议吗?它在我头上。我需要一个表单的KeyPreview之类的东西,但对于鼠标单击,它会找出单击了什么VCL组件,并确定它的.Tag值

汤姆

编辑:

根据David H.的建议,我得到的唯一事件是当应用程序获得焦点或失去焦点时。我做错了什么

    function TForm1.AppHookFunc(var Message : TMessage) : Boolean;
    begin
      Result := FALSE;
      inc(i); outputdebugstring(Pchar(inttostr(i) + ': ' + IntTostr(Message.msg)));
      if Message.Msg = WM_MBUTTONDOWN then
        begin      Beep;
        //...DoSomething...
        //Result := True;
        end;
    end;

    procedure TForm1.FormCreate(  Sender: TObject);
    begin
      Application.HookMainWindow(AppHookFunc);
    end;

    procedure TForm1.FormDestroy(
      Sender: TObject);
    begin
      Application.UnHookMainWindow(AppHookFunc);
    end;
编辑2

我快到了!但是finddraggtarget很少返回除nil之外的任何内容。如果我制作一个覆盖大部分控件的巨大按钮,我有时可以让它工作。接收到的tagMSG中的X、Y坐标相对于控件。我认为它们是相对于表格的。我是否仍在使用不同的事件挂钩?任何建议:

  procedure TForm1.ApplicationEvents1Message( var Msg: tagMSG;
                                              var Handled: Boolean);
  var
    Target: TControl;
    Point: TPoint;
  begin
    Handled := FALSE;
    if (Msg.Message = WM_LBUTTONDOWN) And isAltDown then
      begin
        Point.X := LongRec(Msg.lParam).Lo;
        Point.Y := LongRec(Msg.lParam).Hi;
        Target := FindDragTarget( Point, {AllowDisabled=}TRUE);
        if Assigned(Target) then
          begin
            if Target Is TButton then
              outputdebugString(Pchar(TButton(Target).Caption));
          end
        else
          outputdebugstring(Pchar(IntToStr(Point.X) + ', ' + IntToStr(Point.Y)));
      end;
  end;
最终编辑:

我将上面的代码更改为使用GetCursorPos而不是Msg.lParam。它正在工作。很酷!太棒了


谢谢你们两位的帮助

我假设这是一个VCL应用程序。对于FireMonkey来说,这是行不通的

  • 添加
    应用程序.OnMessage
    事件处理程序
  • 在事件处理程序中,查找
    WM_LBUTTONDOWN
    WM_LBUTTONUP
    ,并检查修改器键状态是否如您所愿,例如CTRL键已按下
  • 调用传递与鼠标事件关联的位置。如果确实存在鼠标控制(即检查
    nil
    ),则这将为您提供鼠标控制
  • 做你想做的任何事来控制它

  • 如果对
    TWinControl
    子体进行翻译就足够了,那么您可以尝试使用函数确定鼠标下的控件,并从应用程序外部通过
    WM_GETTEXT
    WM_SETTEXT
    获取/设置其文本。不要挂接主窗口。分配Application.OnMessage。或者使用TApplicationEvents。支持非TWinControl控件非常简单,无需切换到
    TStaticText
    。使用
    FindDragTarget()
    而不是
    FindVCLWindow()
    FindDragTarget()
    在内部调用
    FindVCLWindow()
    ,如果找到它,则调用该控件的
    ControlAtPos()
    方法来检查非TWinControl子控件。@remy谢谢。我现在有点不舒服。我很高兴您能将这些信息作为编辑,甚至是单独的答案添加进来。@remy我已经再次决定并更新了这个问题。谢谢你教我一些我不知道的东西。再一次。我爱死你了!很抱歉一直打扰你,大卫。如何从tagMSG中提取keystate以及x和y?我倾向于懒惰,只需调用。但它包含在鼠标消息中。在本例中,您可以测试
    wParam和MK_CONTROL=MK_CONTROL
    来测试CTRL-down。注意
    MK_控件=$0008
    。您可能希望通过确保其他修改器未关闭来检查是否只按下CTRL键。