枚举Delphi中已发布的属性和子属性 [英] Enumerating published properties and subproperties in Delphi

查看:126
本文介绍了枚举Delphi中已发布的属性和子属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很抱歉以前是否提出这个问题。我对某些组件的定义如下(如果是错误的,请指导我,因为我是初学者)。我正在尝试枚举派生组件的所有已发布属性,尤其是子属性。我可以枚举属性的名称,但是,是否可以枚举在程序执行期间可以访问其元素的已发布属性(如子属性)?像返回getFirst / getnext这样的属性直到结束?

Apologies if the question was asked before. I have some definition of some components as follows (please guide me if it's wrong, because I'm a beginner). What I am trying, is to enumerate all published properties of the derived components, particularly the sub-properties. I am able to enumerate the names of the properties, however, is it possible to enumerate the published properties for which I can access the elements (as in the sub-properties) during the execution of the program? something like returning properties one-by-one like getfirst / getnext until to the end?

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;

任何要点或准则(示例代码)都受到高度赞赏。
预先感谢。

Any points or guidelines (sample code) is highly appreciated. Thanks in advance.

推荐答案

虽然它没有具体回答您的问题,但下面的代码(捐赠给了几年前由TeamB的Peter Under博士撰写的Borland Delphi旧新闻组展示了如何使用RTTI克隆另一个组件。它显示了如何获取(和设置)子属性,例如其他对象,枚举类型等等。它应该足以使您入门。我已经在代码中留下了Peter的注释,并以该函数下方的一些示例代码的形式保留了使用它的示例。 (我还保留了他的代码格式和某些关键字的奇怪字母大小写。:)

While it doesn't specifically answer your question, the code below (donated to the old Borland Delphi newsgroups a few years ago by Dr. Peter Below of TeamB) shows how to use RTTI to clone another component. It shows how to get (and set) sub-properties like other objects, enumerated types, and so forth. It should be enough to get you started. I've left Peter's comments in the code, as well as a sample of using it in the form of some sample code below the function. (I've also preserved his code formatting and strange letter casing of some keywords. :)

// 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;

这篇关于枚举Delphi中已发布的属性和子属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆