如何检测其他控件何时更改?

时间:2013-12-15 17:42:52

标签: delphi delphi-xe2

我有一个自定义TLabel原则上可以附加到表单中的任何其他可视组件。该组件具有属性position,该属性告知它将朝向附加控件(左侧,上方等)定位。附加相关控件时,此工作正常,并且组件根据position属性定位自身。

问题是当相关控件改变它的界限时我无法检测组件,因此它可以正确地重新定位自己。我想这与WMMoveWMResize有关。如何让相关控件通知TLabel任何边界属性已更改?

2 个答案:

答案 0 :(得分:7)

只要控件的位置和/或尺寸发生变化,就会触发控件的OnResize事件。因此,一个简单的解决方案是在将Label附加到控件时为该事件分配处理程序,例如:

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;

当然,如果用户想要将自己的OnResize处理程序分配给控件,这将导致问题。

另一种方法是改为控制WindowProc属性的子类:

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;

答案 1 :(得分:4)

基于@RemyLebeau的回答以及来自ExtCtrls.TLabeledEdit的一些概念想法,我编写了自己的TStickyLabel控件。 (工作正在进行中)。雷米的回答应该被接受当然:)