如何复制控件的全部属性(200分)(0)

  • 主题发起人 主题发起人 SupermanTm
  • 开始时间 开始时间
S

SupermanTm

Unregistered / Unconfirmed
GUEST, unregistred user!
窗口中预先在设计期防置了一个控件(按钮或者别的什么)并连接好相应的事件和属性,程序在运行期间根据配置需要创建多个相同的控件(只有一个ID不同),用什么方法可以直接复制属性到新的控件。本帖不直接给分数了,因为我在 http://www.delphibbs.com/delphibbs/dispq.asp?lid=3463402 给出的分数终于没用上,如能帮上忙的,将在那里给分吧
 
A:=TButton.Create(self); B.Assign(A);
 
用流。楼上的代码 估计不行。TButton类根本没有覆盖这个虚方法。
 
TButton类覆盖了Assign方法。
 
ComPersist := TComPersister.Create(self); MStream := TMemoryStream.Create; List := TList.Create; MStream.Clear; try List.Clear; List.Add(Panel1); ComPersist.SaveComsToStream(MStream, List); finally List.Free; end; MStream.Position := 0; ComPersist.LoadComsFromStream(MStream, sheettemp);
 
关键代码:ComPersist := TComPersister.Create(self);ComPersist.SaveComsToStream(MStream, List);ComPersist.LoadComsFromStream(MStream, sheettemp); sheettemp上放置panel1复制panel1的属性和事件
 
TButton类覆盖了Assign方法。 ?? TButton = class(TButtonControl) private FDefault: Boolean; FCancel: Boolean; FActive: Boolean; FModalResult: TModalResult; procedure SetDefault(Value: Boolean); procedure CMDialogKey(var Message: TCMDialogKey); message CM_DIALOGKEY; procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR; procedure CMFocusChanged(var Message: TCMFocusChanged); message CM_FOCUSCHANGED; procedure CNCommand(var Message: TWMCommand); message CN_COMMAND; procedure CNCtlColorBtn(var Message: TWMCtlColorBtn); message CN_CTLCOLORBTN; procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; protected procedure CreateParams(var Params: TCreateParams); override; procedure CreateWnd; override; procedure SetButtonStyle(ADefault: Boolean); virtual; public constructor Create(AOwner: TComponent); override; procedure Click; override; function UseRightToLeftAlignment: Boolean; override; published property Action; property Anchors; property BiDiMode; property Cancel: Boolean read FCancel write FCancel default False; property Caption; property Constraints; property Default: Boolean read FDefault write SetDefault default False; property DragCursor; property DragKind; property DragMode; property Enabled; property Font; property ModalResult: TModalResult read FModalResult write FModalResult default 0; property ParentBiDiMode; property ParentFont; property ParentShowHint; property PopupMenu; property ShowHint; property TabOrder; property TabStop default True; property Visible; property WordWrap; property OnClick; property OnContextPopup; property OnDragDrop; property OnDragOver; property OnEndDock; property OnEndDrag; property OnEnter; property OnExit; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnStartDock; property OnStartDrag; end;
 
试过了,Assign 方法不行,我用的是 TSpeedButton 按钮
 
重载assign方法,是最彻底的办法,不过要在控件上派生新类,太麻烦,不实用。对于可视化控件来说,他们的外观属性基本上都是published的。可以用RTTI来直接遍历其published的属性,然后在新的控件上给赋值,就可以得到原有控件上所有的属性方法,对于界面控件的复制肯定是没问题的。先前我也这样用过,不过你要对RTTI的机制要了解才行。自delphi2009出来后,据说添加了反射机制,但是并不太好用,也能实现你的要求。
 
呵呵,不好意思我理解错了TButton确实没覆盖Assign
 
“可以用RTTI来直接遍历其published的属性,然后在新的控件上给赋值,就可以得到原有控件上所有的属性方法,对于界面控件的复制肯定是没问题的”有无近似的参考例程借鉴一下呢?
 
这是很久以前做的了,将控件给流化,就是将控件的特征转化成字符串,传递到另一台机器上,然后在另一台机器上还原。可以做到远程的界面复制。因为代码不在我现在的机器上,只找到其中类似的代码片段,以供你参考,如果你看不懂的话,你就需要补充RTTI的基本知识了。祝你好运procedure TtxStreamData.FromString(AData: String);var iLen: Integer; strDate: string; procedure LoadPropertyValue(AObject: TObject); var _PropList: PPropList; i, j: integer; begin if not Assigned(AObject) then Exit; for i := 0 to GetPropList(AObject, _PropList) - 1 do begin if _PropList.PropType^.Kind in [tkString, tkLString, tkWString] then begin SetStrProp(AObject, _PropList.Name, StringToValue(_PropList.Name)); end; if _PropList.PropType^.Kind in [tkInteger] then begin SetOrdProp(AObject, _PropList.Name, StringToInteger); end; if _PropList.PropType^.Kind in [tkInt64] then begin SetInt64Prop(AObject, _PropList.Name, StringToInteger); end; if _PropList.PropType^.Kind in [tkFloat] then begin SetFloatProp(AObject, _PropList.Name, StringToFloat); end; if _PropList.PropType^.Kind in [tkEnumeration] then begin SetEnumProp(AObject, _PropList.Name, StringToValue(_PropList.Name)); end; // tkChar, tkEnumeration, , // tkSet, tkClass, tkWChar, // tkVariant, tkArray, tkRecord, tkInterface, , tkDynArray if _PropList.PropType^.Kind = tkClass then begin LoadPropertyValue(GetObjectProp(AObject, _PropList)); end; end; Dispose(_PropList); if AObject is TCollection then begin TCollection(AObject).Clear; { TODO : 2007-02-24 update } //必须将数量给写上去 j := StringToInteger; for i := 0 to j - 1 do begin LoadPropertyValue(TCollection(AObject).Add); end; end end;begin strDate := DecodeBase64(AData); /// strDate := DecodeString(AData); iLen := Length(strDate); FStringStream.Size := 0; FStringStream.Write(PChar(strDate)^, iLen); FStringStream.Position := 0; LoadPropertyValue(Self);end;
 
stream: tstringstream;stream.WriteComponent(srcComponent);stream中的内容就是脚本代码, 还个新namedesComponent := stream.ReadComponent(desComponent );将脚本转化成控件
 
1982的方法简洁明了。不过如果我需要对特定的属性进行编辑怎么办?
 
stream: tstringstream;stream.WriteComponent(srcComponent);desComponent := stream.ReadComponent(desComponent );这里已经有控件了,对于特定属性的赋值就更简单了:TEdit(desComponent).属性 := ......我以前一个程序要求程序重新打开时恢复上一次的控件里内容等,我是这样写的:关闭时把控件保存起来,打开时再读出来。close事件中保存控件或窗体:var sStream: TStream;begin sStream := TFileStream.Create('d:/edt1.edt', fmCreate); try sStream.WriteComponent(edt1); finally FreeAndNil(sStream); end;end;打开时读取:var sStream: TStream;begin sStream := TFileStream.Create('d:/edt1.edt', fmOpenRead); try edt1 := TMemo(sStream.ReadComponent(nil)); edt1.Parent := Self; edt1.Show; finally FreeAndNil(sStream); end;end;记得在初使化时要注册TEdit类RegisterClass(TEdit);可以参考类似的写法
 
andywang,的不行,tbutton的onclick 没有复制
 
apiao,的方法可以
 
好像还是太复杂了,还不如直接一行一行写了for I:= 0 to BtnCount - 1 do begin MyBtn:= TSpeedButton.Create(Self); MyBtn.Parent:= SampleBtn.Parent; MyBtn.OnClick:= SampleBtn.OnClick; MyBtn.OnDblClick:= SampleBtn..OnDblClick; ... MyBtn.Tag:= I;end;不管怎么说,谢谢诸位的支持,分数还是照给吧,请 apiao, andywang, let_it_be 到帖子: http://www.delphibbs.com/delphibbs/dispq.asp?lid=3463402 领分数吧
 
后退
顶部