在任何VCL组件上单击鼠标,并确定其.Tag值 [英] Catch a mouse click on any VCL component, and determine its .Tag value
问题描述
我的翻译者抱怨翻译一长串字符串很困难,因为他们没有在上下文中看到他们(在他们出现的屏幕上)。
$一个翻译人员提出了一个很好的建议,他应该可以点击一个组件来改变它的文本。我可以实现这个 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,这将不起作用。
- 添加一个
Application.OnMessage
事件处理程序。 - 在事件处理程序中查找
WM_LBUTTONDOWN
或者可能WM_LBUTTONUP
并检查修改器键状态是你想要的,例如CTRL已关闭。 - 致电
FindDragTarget
传递与鼠标事件关联的位置。这将给你鼠标下的控制,如果确实有一个(即检查nil
)。 - 做任何事情你想要这个控制。
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.
- Add an
Application.OnMessage
event handler. - In the event handler look for
WM_LBUTTONDOWN
or perhapsWM_LBUTTONUP
and check that the modifier key state is as you desire, e.g. CTRL is down. - 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 fornil
). - Do whatever it is you want to that control.
这篇关于在任何VCL组件上单击鼠标,并确定其.Tag值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!