Catch a mouse click on any component of VCL and determine its value .Tag

I use a homemade translation tool. (Next time I will use one of the libraries as described here: the delphi translation tool .)

My translators complain that translating a long list of lines is difficult because they do not see them in context (on the screen on which they appear.)

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

(Each translated component has a unique integer in its tag, which I use to search for the .Caption component.)

Any suggestions on how to do this? It is above my head. I need something like a KeyPreview form, but for mouse clicks that could determine what the VCL component was typed on and define it. Tag value.

Tom

EDIT:

Using David H.'s suggestion, the only events I get are when the application gains focus or loses it. What did I do 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 here! But FindDragTarget rarely returns anything but zero. If I make a huge button that covers most of the control, I can sometimes make it work. The X, Y coordinates in the resulting MSG tag are relative to the control. I would like them to relate to form. I'm still using a different event hook, what should I? 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; 

COMPLETION:

I changed the code above to use GetCursorPos instead of Msg.lParam. He is working now. Very cool! SO Rocks!

THANKS FOR YOUR HELP!

+8
delphi
source share
2 answers

I assume this is a VCL application. For FireMonkey, this will not work.

  • Add an Application.OnMessage event handler.
  • In the event handler, find WM_LBUTTONDOWN or, possibly, WM_LBUTTONUP and make sure that the state of the modifier key is as you wish, for example. CTRL does not work.
  • Call FindDragTarget , passing the position associated with the mouse event. This will give you control under the mouse if there really is one (e.g. check nil ).
  • Do whatever you want for this control.
+10
source share

For Delphi 6, the FindDragTarget (Point, true) function does not work properly. In its internal code, the FindVCLWindow (Pos) function always returns nil. Finally, the Application.OnMessage event handler:

 procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG; var Handled: Boolean); var Control: TControl; Point: TPoint; Window: TWinControl; Handle: HWND; ShiftState: TShiftState; begin Handled := false; if (Msg.Message = WM_LBUTTONUP) then begin ShiftState := KeysToShiftState(Msg.wParam);//Get modifier keys state Point.X := LongRec(Msg.lParam).Lo; Point.Y := LongRec(Msg.lParam).Hi; Control := FindControl(Msg.hwnd); //Try get TWinControl Window := Self; if (Control = Window) then //Possible TControl Control := nil; if not Assigned(Control) then begin Control := Window.ControlAtPos(Point, true, true); if not Assigned(Control) then begin //Try get child control for disabled TControl or TPanel Handle := ChildWindowFromPoint(Window.Handle, Point); Control := FindControl(Handle); end; end; end; end; 
-one
source share

All Articles