1

我有一个 TUpDown 控件,其 Associate 设置为 TEdit 子类的实例。编辑类在其重写的 DoEnter 方法中调用 RecreateWnd。不幸的是,这会在 API 级别杀死伙伴连接,从而导致奇怪的行为,例如单击向上箭头时。

我的问题是编辑实例不知道它是应该重新连接的某个 updown 的伙伴,并且 updown 没有收到失去其伙伴的通知。有什么想法可以重新连接两者吗?

4

3 回答 3

2

我注意到 TCustomUpDown.SetAssociate 如何检查 updown 和 buddy 是否具有相同的父级,并使用它来避免重复关联。所以我尝试调用我自己的 RecreateWnd 方法:

procedure TAlignedEdit.RecreateWnd;
var
  i: Integer;
  c: TControl;
  ud: TCustomUpDown;
begin
  ud := nil;
  for i := 0 to Pred(Parent.ControlCount) do
  begin
    c := Parent.Controls[i];
    if c is TCustomUpDown then
      if THACK_CustomUpDown(c).Associate = Self then
      begin
        ud := TCustomUpDown(c);
        Break;
      end;
  end;
  inherited RecreateWnd;
  if Assigned(ud) then
  begin
    THACK_CustomUpDown(ud).Associate := nil;
    THACK_CustomUpDown(ud).Associate := Self;
  end;
end;

et voila - 它有效!

于 2009-09-01T13:14:32.660 回答
1

你发现了一些相当不幸的事情。您在应用程序级别设置了两个控件之间的关联,因此您应该能够继续在应用程序级别代码中管理该关联,但 VCL 不提供维护它所需的框架。理想情况下,会有一个通用的关联框架,因此关联的控件可以相互通知他们应该更新自己。

VCL 有这方面的开始,使用Notification方法,但只通知组件被销毁。

我认为您提出的解决方案对任务来说有点过于具体。编辑控件不一定知道它附加到上下控件,即使知道,也不应该要求它们共享父控件。另一方面,为这个问题编写一个完整的通用观察者框架将是矫枉过正。我提议妥协。

从编辑控件上的新事件属性开始:

property OnRecreateWnd: TNotifyEvent read FOnRecreateWnd write FOnRecreateWnd;

然后像上面那样覆盖RecreateWnd,但不是所有特定于上下控制的代码,只需触发事件:

procedure TAlignedEdit.RecreateWnd;
begin
  inherited;
  if Assigned(OnRecreateWnd) then
    OnRecreateWnd(Self);
end;

现在,在您的应用程序代码中处理该事件,您可以确切地知道哪些控件相互关联,因此您不必搜索任何内容,也不需要任何父子关系:

procedure TUlrichForm.AlignedEdit1RecreateWnd(Sender: TObject);
begin
  Assert(Sender = AlignedEdit1);
  UpDown1.Associate := nil;
  UpDown1.Associate := AlignedEdit1;
end;
于 2009-09-01T17:37:37.130 回答
0

尝试在调用 RecreateWnd 之前将 Associate 属性的值存储在局部变量中,然后再将其设置回来。

于 2009-09-01T12:54:13.917 回答