Delphi - Наследование визуальной формы - Определение базового класса компонентов

Я использую VFI (наследование визуальной формы), и мне нужно проверить, принадлежит ли компонент созданной формы к классу формы или к суперклассу формы.

Любые идеи ?

  unit1

  TFormStatus = class(TForm)
    cpPanel: TPanel;
    lblStatus: TLabel;
  end;

  unit 2

  TFormCodigo = class(TFormStatus)
    lblCodigo: TLabel;
  end;

  frmCodigo: TFormCodigo:

Во всех случаях использования frmCodigo я хочу обнаружить, что lblCodigo является локальным для TFormCodigo, а cpPanel / lblStatus являются унаследованными компонентами;

  for i:=0 to Self.ComponentCount-1 do begin        
      if "InheritedComponent" (Self.Components[i]) then ...
  end;

Что-то подобное возможно с использованием RTTI для свойств объекта, но я не знаю, возможно ли это для компонентов.

Спасибо.


person Vic    schedule 17.01.2011    source источник
comment
Настоящий вопрос: Почему вы хотите знать? Я уверен, что есть правильные OO-решения проблемы, стоящей за этим вопросом. (Скорее всего, виртуальные методы.)   -  person Uli Gerhardt    schedule 17.01.2011
comment
@Ulrich Что ж, OP может работать над каким-то фреймворк-подобным кодом, который хочет самопровериться. Но да, мне было бы любопытно понять мотивацию этого вопроса.   -  person David Heffernan    schedule 17.01.2011
comment
@David: Опубликованный код выглядит очень конкретным - никаких рамок не видно. :-)   -  person Uli Gerhardt    schedule 17.01.2011
comment
Мне кажется, что любое решение, которое не смотрит в ресурс DFM, будет неполным. В DFM могут быть определены компоненты, которые не хранятся ни в одном поле класса. (Просто очистите свойство Name в инспекторе объектов.) Такой компонент не будет отображаться в определении класса, но я предполагаю, что вы все равно захотите узнать, какой класс формы внес этот элемент управления в последний экземпляр.   -  person Rob Kennedy    schedule 17.01.2011
comment
Если вы готовы пойти по пути хакерства, вы можете использовать находки Холлварда Вассботна на его сведения об опубликованных полях, чтобы узнать, какой компонент к какому классу принадлежит.   -  person Sertac Akyuz    schedule 21.01.2011


Ответы (3)


Если я вас правильно понял, вам нужен TRttiMember.Parent. Например, см. Эту статью Роба Лава. Думаю, вам понадобится Delphi 2010 или новее.

На самом деле это всего лишь часть отличная серия статей - в этих статьях также рассказывается, как получить поля, свойства и т. д., не зная их имен.

person David Heffernan    schedule 17.01.2011
comment
Как вы говорите, это отличные изделия. Я использую Delphi 2007. Я пытался получить доступ к компонентам с помощью RTTI без выхода. Я хочу записать в файл конфигурации значения некоторых свойств ненаследуемых компонентов (как это делает Delphi в файлах FRM, используя «объект» для локальных компонентов и «унаследованный» для унаследованных компонентов). Delphi обнаруживает это наследование в Object Inspector, показывая дерево свойств с соответствующим наследованием классов. - person Vic; 19.01.2011
comment
Delphi обнаруживает это наследование в окнах локальных переменных во время отладки, показывая дерево свойств с соответствующим наследованием классов. - person Vic; 19.01.2011

Может, что-нибудь "глупое" вроде

function TFormStatus.IsStatusComponent(AComponent: TComponent): Boolean;
begin
  Result := (AComponent = cpPanel) or (AComponent = lblStatus);
end;

уже удовлетворяет ваши потребности?

person Uli Gerhardt    schedule 17.01.2011
comment
Нет. Во время выполнения я не знаю компонентов формы-предка. - person Vic; 19.01.2011

В вашем TFormCordigo вы можете переопределить метод ReadState, который вызывается каждый раз при чтении ресурса для определенной формы. После того, как унаследованный, вызываемый ComponentCount содержит количество компонентов, созданных до текущего члена иерархии, поэтому в конце концов у вас есть список границ для компонентов, которые вы можете сохранить в другом месте.

Код ниже иллюстрирует этот подход.

procedure TInhTestForm.Button3Click(Sender: TObject);
var
  i: integer;
begin
  inherited;

  Memo1.Lines.Clear;
  for i:=0 to ComponentCount-1 do
  begin
    Memo1.Lines.Add(format('%s inroduced in %s', [Components[i].Name, ComponentParent(i).ClassName]));
  end;
end;

function TInhTestForm.ComponentParent(Index: integer): TClass;
var
  i, j: integer;
begin
  Result:=Nil;
  for i:=Low(fComponentBorders) to High(fComponentBorders) do
  begin
    if Index <= fComponentBorders[i] - 1 then
    begin
      j:=i;
      Result:=Self.ClassType;
      while j < High(fComponentBorders) do
      begin
        Result:=Result.ClassParent;
        Inc(j);
      end;
      break;
    end;
  end;
end;

procedure TInhTestForm.ReadState(Reader: TReader);
begin
  inherited;
  SetLength(fComponentBorders, Length(fComponentBorders) + 1);
  fComponentBorders[High(fComponentBorders)]:=ComponentCount;
end;
person Maksee    schedule 20.01.2011
comment
Я нашел решение, создавая новый экземпляр формы и новый экземпляр class-parent-form и сравнивая списки их компонентов. Это также может быть полезно для сравнения значений их свойств по умолчанию. - person Vic; 21.01.2011
comment
Я также пробовал использовать TWriter для динамической перезаписи FRM. Хорошее решение, но очень сложное для моих нужд (только определять, унаследован ли компонент) - person Vic; 21.01.2011