在任何VCL组件上单击鼠标,并确定其.Tag值 [英] Catch a mouse click on any VCL component, and determine its .Tag value

查看:176
本文介绍了在任何VCL组件上单击鼠标,并确定其.Tag值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

$一个翻译人员提出了一个很好的建议,他应该可以点击一个组件来改变它的文本。我可以实现这个 if ,我可以找到一个方法来钩子程序,一个事件,以便当用户在按住CTRL键的同时点击一个组件时,调用一个事件处理程序。事件处理程序将确定组件是否具有.Caption属性,如果是,则获取Tag组件的值(然后允许某些用户输入)。



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



有关如何解决这个问题的任何建议?这是我的头。我需要一些类似表单的KeyPreview,但是鼠标点击可以看出VCL组件被点击,并确定它的.Tag值。



Tom



编辑:



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

  function TForm1.AppHookFunc(var Message:TMessage):Boolean; 
begin
结果:= FALSE;
inc(i); outputdebugstring(Pchar(inttostr(i)+':'+ IntTostr(Message.msg)));
如果Message.Msg = WM_MBUTTONDOWN然后
begin Beep;
// ... DoSomething ...
//结果:= True;
结束
结束

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

procedure TForm1.FormDestroy(
Sender:TObject);
begin
Application.UnHookMainWindow(AppHookFunc);
结束

编辑2



我几乎那里!但是FindDragTarget很少返回任何东西,但是没有。如果我做了一个巨大的按钮覆盖了大部分的控制,我有时可以让它上班。接收到的标签MSG中的X,Y坐标是相对于控件。我会尽可能相对于表格。我还在使用一个不同于我应该的事件钩子吗?任何建议:

 程序TForm1.ApplicationEvents1Message(var Msg:tagMSG; 
var Handled:Boolean);
var
目标:TControl;
点:TPoint;
begin
处理:= FALSE;
if(Msg.Message = WM_LBUTTONDOWN)然后isAltDown然后
begin
Point.X:= LongRec(Msg.lParam).Lo;
Point.Y:= LongRec(Msg.lParam).Hi;
目标:= FindDragTarget(Point,{AllowDisabled =} TRUE);
如果分配(目标)然后
开始
如果目标是TButton然后
outputdebugString(Pchar(TButton(目标).Caption));
end
else
outputdebugstring(Pchar(IntToStr(Point.X)+','+ IntToStr(Point.Y)));
结束
结束

FINAL EDIT:



以上代码使用GetCursorPos而不是Msg.lParam。它现在正在工作很酷!



谢谢你的帮助!

解决方案

我假设这是一个VCL应用程序。对于FireMonkey,这将不起作用。


  1. 添加一个 Application.OnMessage 事件处理程序。

  2. 在事件处理程序中查找 WM_LBUTTONDOWN 或者可能 WM_LBUTTONUP 并检查修改器键状态是你想要的,例如CTRL已关闭。

  3. 致电 FindDragTarget 传递与鼠标事件关联的位置。这将给你鼠标下的控制,如果确实有一个(即检查 nil )。

  4. 做任何事情你想要这个控制。


I'm using a home-grown translation tool. (Next time I'll use one of the libraries, as described here: delphi translation tool.)

My translators complain that translating a long list of strings is difficult because they're not seeing them in context (on the screen in which they appear.)

One translator made a great suggestion that he should be able to click on a component to change its text. I can implement this if I can find an way to hook program wide, an event so that when a user clicks on a component while holding down the CTRL key, an event handler is called. The event handler would determine if the component has a .Caption property, and if so, get the value of the Tag component (and then allow some user input.)

(Each translatable component has unique integer in its Tag properly, which I use to look up the component's .Caption.)

Any suggestions on how to go about this? It's over my head. I need something like a form's KeyPreview, but for mouse-clicks that would figure out what VCL component was clicked, and determine it's .Tag value.

Tom

EDIT:

Using David H.'s suggestion, the only events I get are when the app gets focus or loses it. What have I done wrong?

    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;

EDIT 2

I'm almost there! But FindDragTarget seldom returns anything but nil. If I make an enormous button covering most of the control, I can sometimes get it to work. The X,Y coordinates in the tagMSG received are relative to the control. I would have though they'd relative to the form. Am I still using a different event hook than I should? Any suggestions:

  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;

FINAL EDIT:

I changed the code above to use GetCursorPos rather than Msg.lParam. It's working now. Very cool! SO Rocks!

THANK YOU BOTH FOR YOUR HELP!

解决方案

I'm assuming this is a VCL app. For FireMonkey this would not work.

  1. Add an Application.OnMessage event handler.
  2. In the event handler look for WM_LBUTTONDOWN or perhaps WM_LBUTTONUP and check that the modifier key state is as you desire, e.g. CTRL is down.
  3. Call FindDragTarget passing the position associated with the mouse event. This will give you the control under the mouse, if indeed there is one (i.e. check for nil).
  4. Do whatever it is you want to that control.

这篇关于在任何VCL组件上单击鼠标,并确定其.Tag值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆