Delphi 如何检测其他控件何时更改其边界?
我有一个自定义的Delphi 如何检测其他控件何时更改其边界?,delphi,delphi-xe2,Delphi,Delphi Xe2,我有一个自定义的TLabel,原则上可以附加到表单中的任何其他可视组件。组件有一个属性position,该属性告诉它将朝向附加控件(左侧、上方等)放置的位置。如果附加了相关控件,并且组件根据position属性对其自身进行定位,则此功能可以正常工作 问题是,我无法让组件在相关控件改变其边界时进行检测,以便它能够正确地重新定位自身。我想这与WMMove和WMResize有关。如何使相关控件通知TLabel任何边界属性已更改?每当控件的位置和/或尺寸更改时,就会触发控件的OnResize事件。因此,
TLabel
,原则上可以附加到表单中的任何其他可视组件。组件有一个属性position
,该属性告诉它将朝向附加控件(左侧、上方等)放置的位置。如果附加了相关控件,并且组件根据position
属性对其自身进行定位,则此功能可以正常工作
问题是,我无法让组件在相关控件改变其边界时进行检测,以便它能够正确地重新定位自身。我想这与
WMMove
和WMResize
有关。如何使相关控件通知TLabel
任何边界属性已更改?每当控件的位置和/或尺寸更改时,就会触发控件的OnResize
事件。因此,一个简单的解决方案是在将标签附加到控件时为该事件指定一个处理程序,例如:
private
FControl: TControl;
// OnResize is protected in TControl so use an accessor class to reach it...
type
TControlAccess = class(TControl)
end;
procedure TMyLabel.Destroy;
begin
SetControl(nil);
inherited;
end;
procedure TMyLabel.SetControl(AControl: TControl);
begin
if FControl <> AControl then
begin
if FControl <> nil then
begin
TControlAccess(FControl).OnResize := nil;
FControl.RemoveFreeNotification(Self);
end;
FControl := AControl;
if FControl <> nil then
begin
FControl.FreeNotification(Self);
TControlAccess(FControl).OnResize := ControlResized;
end;
...
end;
end;
procedure TMyLabel.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = FControl) then
FControl := nil;
end;
procedure TMyLabel.ControlResized(Sender: TObject);
begin
// reposition as needed...
end;
基于@RemyLebeau答案和
ExtCtrls.TLabeledEdit
中的一些概念想法,我编写了自己的控件。(正在进行的工作)。当然,雷米的回答应该被接受:)这是一个TControl还是TWinControl?也就是说,它是否有窗口句柄?我认为您几乎需要考虑制作一个可以包含相关控件的TPanel。您的tlabelothercontrol
可以通过TSmartLayoutPanel
进行管理,它可以查看其中的所有控件,并知道它们何时移动。我真的不认为我会想要一个TLabel在拥有它的表单上做各种粗俗的钩子。看看Swing如何使用布局管理(Java)来获得一些灵感。如果TLabel
组件的父组件将是TControl
的后代,则可以在分配给它时截取它的WindowProc
方法。在这种截获的WindowProc
方法中,您可以查看WM\u WINDOWPOSCHANGED
消息,例如。Hi-Remy。谢谢你的回答!我尝试了子类
解决方案,但它遇到了FControlWndProc(Message)问题代码>。它似乎进入了一个循环。有什么建议吗?“似乎”并不意味着“是”。使用调试器,它实际上在做什么?什么信息被卡住了?代码只是将截获的消息传递给关联的控件进行默认处理,因此不应该存在循环,除非该控件本身递归地生成新消息,或者您自己的代码定位/调整标签的大小对控件产生影响,并使其递归地生成新消息。你能编辑你的问题来显示你处理截获消息的实际代码吗?@RemyLebeau,有件事我不明白:在SetControl
中,你的第二个如果FControl nil then。。end else FControl.WindowProc:=nil代码>正确吗?它不应该是:FControlWndProc:=nil代码>?另外,您不应该在TMyLabel.Notification
和TMyLabel.Destroy
上同时调用SetControl(nil)
吗?@kobik:这是一个输入错误。它应该是FControlWndProc
而不是FControl.WindowProc
。如果在控件释放之前标签被释放,那么在析构函数中调用SetControl(nil)
是有意义的,但是在Notification()中调用它是没有意义的,因为控件正在被释放,所以不需要将控件重置为其以前的状态,只需重置它的本地跟踪。@kobik:yes,如果希望标签在设计器中拖动时跟随控件,则必须这样做。
private
FControl: TControl;
FControlWndProc: TWndMethod;
procedure TMyLabel.Destroy;
begin
SetControl(nil);
inherited;
end;
procedure TMyLabel.SetControl(AControl: TControl);
begin
if FControl <> AControl then
begin
if FControl <> nil then
begin
FControl.WindowProc := FControlWndProc;
FControl.RemoveFreeNotification(Self);
end;
FControl := AControl;
if FControl <> nil then
begin
FControlWndProc := FControl.WindowProc;
FControl.WindowProc := ControlWndProc;
FControl.FreeNotification(Self);
end else
FControlWndProc := nil;
...
end;
end;
procedure TMyLabel.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if (Operation = opRemove) and (AComponent = FControl) then
begin
FControl := nil;
FControlWndProc := nil;
end;
end;
procedure TMyLabel.ControlWndProc(var Message: TMessage);
begin
FControlWndProc(Message);
// now check for position/size messages and reposition as needed...
end;