Поддерживать соединение UpDown-Associate при воссоздании партнера - PullRequest
1 голос
/ 01 сентября 2009

У меня есть элемент управления TUpDown, для которого Associate задан экземпляр подкласса TEdit. Класс редактирования вызывает RecreateWnd в своем переопределенном методе DoEnter. К сожалению, это убивает соединение друзей на уровне API, что приводит к странному поведению, например при нажатии на стрелки обновления.

Моя проблема в том, что экземпляр edit не знает, что он является приятелем какого-либо обновления, к которому он должен повторно подключиться, и обновление не уведомляется о потере своего друга. Любые идеи, как я мог бы восстановить два?

Ответы [ 3 ]

2 голосов
/ 01 сентября 2009

Я заметил, как 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 вуаля - это работает!

1 голос
/ 01 сентября 2009

Вы обнаружили что-то довольно неудачное. Вы устанавливаете связь между двумя элементами управления на уровне приложения, так что вы должны иметь возможность продолжать управлять этой связью в коде уровня приложения, но 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;
0 голосов
/ 01 сентября 2009

Попробуйте сохранить значение свойства Associate в локальной переменной перед вызовом RecreateWnd, а затем установить его обратно.

...