Delphi получает значения свойств компонентов формы - PullRequest
1 голос
/ 19 апреля 2010

Я реализую функцию Boilerplate - позволяет пользователям изменять описания некоторых компонентов - например, TLabel s - во время выполнения. например,

TFooClass = Class ( TBaseClass)
 Label : Tlabel;
 ...
 End;

 Var FooClass : TFooClass;

...

Во время разработки свойство заголовка значения Label называется «Имя», когда приложение запущено, есть функция, которая позволяет пользователю изменить заголовок значение, чтобы сказать «Другое имя». Как только это будет изменено, заголовок для метки экземпляр класса FooClass обновляется немедленно.

Проблема теперь в том, если пользователь по какой-либо причине хочет вернуться к дизайну временное значение, скажем, «Имя», кажется невозможным.

Я могу использовать методы RTTIContext и все такое, но я, в конце концов, кажется требовать экземпляр класса для меня, чтобы изменить значение и, так как это уже изменился - я, кажется, ударил кирпичную стену, обходя ее.

У меня такой вопрос - есть ли способ использовать старые методы RTTI или новый RTTIContext заполнить свойство члена класса без создания экземпляра класса - то есть получить свойство из определения ClassType.

Это фрагмент кода моей попытки сделать это:

  c : TRttiContext;
   z : TRttiInstanceType;
   w : TRttiProperty;
 Aform : Tform;
  ....
 Begin
 .....

   Aform := Tform(FooClass);

   for vCount := 0 to AForm.ComponentCount-1 do begin
    vDummyComponent := AForm.Components[vCount];
    if IsPublishedProp(vDummyComponent,'Caption') then begin
      c := TRttiContext.Create;
       try
         z := (c.GetType(vDummyComponent.ClassInfo) as TRttiInstanceType);
         w := z.GetProperty('Caption');
          if w <> nil  then
             Values[vOffset, 1] := w.GetValue(vDummyComponent.ClassType).AsString
        .....
        .....

....
....

Я получаю всевозможные ошибки, и любая помощь будет принята с благодарностью.

Ответы [ 4 ]

1 голос
/ 20 апреля 2010

Система RTTI не обеспечивает то, что вы ищете. Тип информации в настоящее время определяется только во время компиляции. Начальные значения формы устанавливаются во время выполнения с использованием ресурса DFM. Вы можете изменить значения в Ресурсе DFM в скомпилированном приложении, потому что оно оценивается во время выполнения.

Анализировать и использовать Ресурс DFM, где он хранится, или сделать копию исходного значения во время выполнения. Возможно, в момент первоначального изменения, чтобы уменьшить объем используемой памяти.

Масоны Предложение использования TDictionary<string, TValue> - это то, что я бы использовал. Я хотел бы сохранить эту информацию в базе данных, поскольку ее синхронизация может стать настоящим кошмаром обслуживания.

1 голос
/ 19 апреля 2010

Похоже, вы пытаетесь получить значение определенного свойства, определенного в DFM. Это невозможно сделать с помощью RTTI, поскольку RTTI основан на проверке структуры объекта , как указано в определении его класса. DFM не является частью определения класса; это список свойств, который применяется к объектам после того, как они были созданы из определений классов.

Если вы хотите получить значения свойств элементов управления формы, вам, вероятно, придется их где-то кэшировать. Попробуйте поместить что-то в OnCreate формы, которая проходит через все элементы управления и использует RTTI, чтобы заполнить TDictionary<string, TValue> значениями всех свойств. Затем вы сможете просмотреть их позже, когда они вам понадобятся.

0 голосов
/ 23 апреля 2010

Хорошо - я решил проблему. Хитрость заключается в создании другого экземпляра формы следующим образом:

 procedure ShowBoilerPlate(AForm : TForm; ASaveAllowed : Boolean);
 var
    vCount           : Integer;
    vDesignTimeForm  : TForm;
    vDesignTimeComp  : TComponent;
    vDesignTimeValue : String;
    vCurrentValue    : String;
 begin
   ....
   ....
   vDesignTimeForm :=  TFormClass(FindClass(AForm.ClassName)).Create(AForm.Owner);

   try
     // Now I have two instances of the form - I also need to have at least one
     // overloaded constructor defined for the base class of the forms that will allow for 
     // boilerplating. If you call the default Constructor - no boilerplating
     // is done. If you call the overloaded constructor, then, boilerplating is done.
     // Bottom line, I can have two instances AForm - with boilerplated values and
     // vDesignForm without boilerplated values.
     for vCount := 0 to AForm.ComponentCount-1 do begin
       vDummyComponent := AForm.Components[vCount];
       if Supports (vDummyComponent,IdoGUIMetaData,iGetGUICaption)  then begin
          RecordCount := RecordCount + 1;
          Values[vOffset, 0] := vDummyComponent.Name;
          if IsPublishedProp(vDummyComponent,'Caption') then begin
           vDesignTimeComp := vDesignTimeForm.FindComponent(vDummyComponent.Name);
           if vDesignTimeComp <> nil then begin
             // get Design time values here
              vDesignTimeValue := GetPropValue(vDesignTimeComp,'Caption');
           end;
           // get current boilerplated value here
              vCurrentValue  := GetPropValue(vDummyComponent,'Caption');
         end;
        vOffset := RecordCount;;
       end;
     end;

  finally
    FreeAndNil(vDesignTimeForm);
  end;
end;

В любом случае - спасибо всем за советы.

0 голосов
/ 19 апреля 2010

Если то, что вы пытаетесь достичь, чтобы восстановить значение, которое было установлено во время разработки (то есть, то, которое сохранено в DFM), я бы использовал InitInheritedComponent в качестве отправной точки.

Возможно получить содержимое DFM во время выполнения. Может быть, боль разобрать, хотя.

Проверьте также InternalReadComponentRes.

Обе процедуры можно найти в модуле классов.

...