Перечисление опубликованных свойств и вложенных свойств в Delphi - PullRequest
3 голосов
/ 26 марта 2011

Извиняюсь, если вопрос задавался ранее.У меня есть некоторые определения некоторых компонентов следующим образом (пожалуйста, помогите мне, если это неправильно, потому что я новичок).То, что я пытаюсь, - это перечислить все опубликованные свойства производных компонентов, особенно подсвойства.Я могу перечислить имена свойств, однако можно ли перечислить опубликованные свойства, для которых я могу получить доступ к элементам (как в под-свойствах) во время выполнения программы?что-то вроде возврата свойств по одному, например, getfirst / getnext до конца?

type
  TStringArray = array of string;

  TGenericColumnDef = class(TPersistent)
  private
    fColumnName        : String;
    fColumnNumber      : Integer;
    fColumnDisplay     : string;
    fColumnDescription : string;
    fColumnDataType    : integer;
    fColumnEditorType  : integer;
 //   fMyEvent: TNotifyEvent;
  protected
  public
    constructor create(AOwner: TComponent); virtual;
  published
    property ColumnName   : String read fColumnName write fColumnName;
    property ColumnNumber : integer read fColumnNumber write fColumnNumber;
    //property MyEvent: TNotifyEvent read fMyEvent write fMyEvent;
  end;

 TGenericAsset = class(Tcomponent) //TPersistent
  private
   { Private declarations }
   fCiteID        : TGenericColumnDef;
   fCiteType      : TGenericColumnDef;
   fTitle         : TGenericColumnDef;
   fAuthor        : TGenericColumnDef;

   fPropertyCount : integer;
   function GetPropertyCount    : integer;
   function GetNextPropertyIndex: integer;
   property CountProperties     : integer read GetPropertyCount;// write fPropertyCount
  protected
   { Protected declarations }
   FOwner: TObject;
  public
   { Public declarations }
   constructor Create(AOwner: TComponent); override;
   destructor  destory ; virtual;
   function    GetColumnNameByColumnNumber(ColumnNumber : Integer) : String;
   function    GetColumnNames : TStringArray;
//   function    GetFirst : TGenericColumnDef;
  published
   property CiteID   : TGenericColumnDef read fCiteID write fCiteID;
   property CiteType : TGenericColumnDef read fCiteType write fCiteType;
   property Title    : TGenericColumnDef read fTitle write fTitle;
   property Author   : TGenericColumnDef read fAuthor write fAuthor;
   //property Nthproperty .........
 end;

//derived from TGenericAsset
type
 TEditedBook = class(TGenericAsset)
  private
  protected
  public
  published
   property CiteID   : TGenericColumnDef read fCiteID write fCiteID;
   property Title    : TGenericColumnDef read fTitle write fTitle;
   property Author   : TGenericColumnDef read fAuthor write fAuthor;
 end;

Любые пункты или рекомендации (пример кода) высоко ценятся.Заранее спасибо.

1 Ответ

4 голосов
/ 26 марта 2011

Хотя он не дает конкретного ответа на ваш вопрос, приведенный ниже код (подаренный старым группам новостей Borland Delphi несколько лет назад доктором Питером Белоу из TeamB) показывает, как использовать RTTI для клонирования другого компонента.В нем показано, как получить (и установить) под-свойства, такие как другие объекты, перечисляемые типы и т. Д.Этого должно быть достаточно, чтобы вы начали.Я оставил комментарии Питера в коде, а также пример использования его в виде некоторого примера кода под функцией.(Я также сохранил его форматирование кода и странный регистр букв некоторых ключевых слов.:)

// Unfortunately there is no easy way to "clone" a component in a way that
// will also preserve event handlers. It can be done using run-time type
// information and routines form the TypInfo unit, though. Try the following
// routine. It is only superficially tested.

Uses TypInfo;

{-- CloneComponent ----------------------------------------------------}
{: Make a copy of a component.
@Param anObj is the component to copy
@Param cloneChildren if true and anObj is a TWincontrol then all its
  child controls will also be copied.
@Param aParent is the parent to use if anObj is a TControl.
@Returns the new object reference. It will have the same owner as anObj
  and passes into the responsibility of the caller.
@Precondition anObj <> nil
@Desc The method creates a new object of the same class as anObj and then
  uses TypInfo routines to copy all published properties. The logic used
  for object properties is similar to what the form loading code uses:
  if a property refers to a TComponent the component reference is copied.
  If it refers to a TPersistent descendent the Assign method is used
  to copy the objects contents. Currently TCollections do not receive
  any special treatment, which may be necessary. <BR>
  Note: the routine will not copy any objects *owned* by anObj, so it
  cannot be used as is to clone a top-level container like a form,
  frame, or datamodule. Those can be copied using WriteComponent and
  ReadComponent with a TMemoryStream.
}{ Created 12.4.2002 by P. Below
-----------------------------------------------------------------------}
Function CloneComponent( anObj: TComponent;
                      cloneChildren: Boolean = false;
                      aParent: TWinControl = nil ): TComponent;
Var
  numProps, I : Integer;
  props: PPropList;
  PropInfo: PPropInfo;
  obj, obj2: TObject;
Begin { CloneComponent }
  Assert( Assigned( anObj ));
  Result := TComponentClass( anObj.ClassType ).Create( anObj.Owner );
  Try
    numProps := GetPropList(anObj, props );
    Try
      For I := 0 To numProps - 1 Do Begin
        PropInfo := props^[I];
        Case PropInfo^.PropType^.Kind Of
          tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
            SetOrdProp( Result, propinfo,
                        GetOrdProp( anObj, propinfo ));
          tkFloat:
            SetFloatProp( Result, propinfo,
                          GetFloatProp( anObj, propinfo ));
          tkString, tkLString:
            If not SameText( propinfo^.name, 'Name' ) Then
              SetStrProp( Result, propinfo,
                          GetStrProp( anObj, propinfo ));
          tkWString:
            SetWideStrProp( Result, propinfo,
                            GetWideStrProp( anObj, propinfo ));
          tkMethod:
            SetMethodProp( Result, propinfo,
                           GetMethodProp( anObj, propinfo ));
          tkInt64:
            SetInt64Prop( Result, propinfo,
                          GetInt64Prop( anObj, propinfo ));
          tkVariant:
            SetVariantProp( Result, propinfo,
                            GetVariantProp( anObj, propinfo ));
          tkInterface:
            SetInterfaceProp( Result, propinfo,
                              GetInterfaceProp( anObj, propinfo ));
          tkClass: Begin
             obj := GetObjectProp( anObj, propinfo );
             If Assigned( obj ) Then Begin
               If obj Is TComponent Then
                 SetObjectProp( Result, propinfo, obj )
               Else If obj Is TPersistent Then Begin
                 obj2 := GetObjectProp( result, propinfo, TPersistent);
                 If Assigned( obj2 ) Then
                   TPersistent( obj2 ).Assign( TPersistent(obj));
               End; { If }
             End; { If }
           End; { Case tkClass }
        Else
          // we don't handle these property types:
          // tkArray, tkRecord, tkDynArray
        End; { Case }
      End; { For }
    Finally
      FreeMem( props );
    End; { Finally }
    If anObj Is TControl Then
      TControl( result ).Parent := aParent;
    If cloneChildren and (anObj Is TWinControl ) Then
      For i:= 0 To TWinControl( anObj ).ControlCount-1 Do
        CloneComponent( TWinControl( anObj ).Controls[i], true,
                        TWinControl( Result ) );
  Except
    Result.Free;
    raise
  End; { Except }
End; { CloneComponent }


procedure TForm1.GroupBox1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  memo1.lines.add('Click on groupbox '+(sender as TComponent).Name );
end;

procedure TForm1.Button1Click(Sender: TObject);
Var
  ctrl: TWinControl;
begin
  ctrl := CloneComponent( groupbox1, true, self ) as TWincontrol;
  With ctrl Do
    SetBounds( left, top+height+8, width, height );
  memo1.Lines.add( Format('Controlcount: %d', [ctrl.controlcount]));
end;
...