2010-04-19 54 views
0

我创建了我自己的组件:TPage,它包含子组件TPaper(TPanel)。 问题是,当我在TPaper(填满几乎整个区域)上放置TMemo或TButton等控件时,控件根本无法加载。见下面的例子为什么复合组件无法使用父级控件?

TPaper = class(TPanel) 
    protected 
     constructor Create(AOwner: TComponent);override; 
     destructor Destroy;override; 
    public 
     procedure Paint; override; 
    end; 





TPage = class(TCustomControl) 
    private 
     FPaper:TPaper; 
    protected 
     procedure CreateParams(var Params:TCreateParams); override; 
    public 
     constructor Create(AOwner: TComponent);override; 
     destructor Destroy;override; 

    published 
     property Paper: TPaper read FPaper write FPaper; 
    end; 




constructor TPage.Create(AOwner: TComponent); 
    begin 
    inherited Create(AOwner); 

    PaperOrientation:=poPortrait; 
    PaperSize:=psA4; 
    PaperBrush:=TBrush.Create; 
    PaperBrush.Color:=clWhite; 
    PDFDocument:=Nil; 
    FPaper:=TPaper.Create(Self); 
    FPaper.Parent:=Self; 
    FPaper.SetSubComponent(True); 
    end; 

... Memo1在TPaper(TPanel)在设计时父,但 后按“运行”,它不存在。

procedure TForm1.btn1Click(Sender: TObject); 
begin 
if not Assigned(Memo1) then ShowMessage('I do not exist'); //Memo1 is nil 
end; 

你知道怎么回事吗?

非常感谢

P.S Delphi 7中

当我把TMemo内部TPaper并保存单元(1单元),相关联的DFM文件的检查之后,没有TMemo部件的痕迹。 (这就是为什么它不能加载到应用程序。)

回答

2

塞尔是对的。 Delphi只对它们所在窗体所拥有的组件进行流式处理。为了避免读取表单文件期间发生的EClassNotfound异常(您现在应该至少在dfm文件中看到Tpaper组件),您必须注册该类通过使用RegisterClass函数(在单元类中)。一个好的地方是你的单位的初始化部分。

如果Tpaper的拥有者设为形式是不是一种选择,那么你仍然可以得到德尔福通过重写的getChildren和GetChildOwner方法和应用逻辑TCustomForm想要串流子用途:

TPage = class 
... 
public 
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override; 
    function GetChildOwner:TComponent; override; 
end; 



procedure TPage.GetChildren(Proc: TGetChildProc; Root: TComponent); // this is copied 
var                 // from 
    I: Integer;              // TCustomForm 
    OwnedComponent: TComponent; 
begin 
    inherited GetChildren(Proc, Root); 
    if Root = Self then 
    for I := 0 to ComponentCount - 1 do 
    begin 
     OwnedComponent := Components[I]; 
     if not OwnedComponent.HasParent then Proc(OwnedComponent); 
    end; 
end; 

function TPage.GetChildOwner: TComponent; 
begin 
    inherited; 
    Result:=Self; 
end; 
+0

感谢您的回答。我试图将这个代码片段实现到我的代码中,但它并不像我预期的那样工作。在TPaper内部插入的组件根本不会出现在dfm文件中。 我在帮助中找到了TComponentStyle: csSubComponent \t该组件是组件的子组件,它是其所有者属性的值。与顶层组件不同,子组件不会与它们所在的表单或数据模块一起保存。相反,子组件显示为其所有者已发布属性的值,其已发布的属性和事件将保存在拥有该组件的表单文件中。 – lyborko 2010-04-20 11:49:55

+0

我猜想,我不能指望在TPaper中插入的任何TWinCOntrol都会保存在dfm文件中。 – lyborko 2010-04-20 11:51:53

+0

如何将备忘录插入Tpaper?如果你这样做: AMemo:= Tmemo.create(FPaper)那么很明显,它不会流入dfm。试试AMemo:= TMemo.create(MyPage),看看它是否有效。 – iamjoosy 2010-04-20 13:35:03

0

的问题是5年前,但因为我遇到了同样的问题,并且在网络中找不到可行的解决方案,所以决定在经过多次测试后共享我发现的解决方案。

TClientPanel = class(TCustomControl) 
private 
    procedure WMNCHitTest(var Message: TWMNCHitTest); message WM_NCHITTEST; 
public 
    constructor Create(AOwner: TComponent); override; 
end; 

TMainPanel = class(TCustomControl) 
private 
    FClient: TClientPanel; 
protected 
    function GetChildOwner: TComponent; override; 
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override; 
    procedure ReadState(Reader: TReader); override; 
    procedure CreateComponentEvent(Reader: TReader; ComponentClass: TComponentClass; var Component: TComponent); 
public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override; 
... 
end; 

constructor TClientPanel.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
    ControlStyle := ControlStyle + [csAcceptsControls, csNoDesignVisible]; 
end; 

procedure TClientPanel.WMNCHitTest(var Message: TWMNCHitTest); 
begin 
    if not (csDesigning in ComponentState) then 
    Message.Result := HTTRANSPARENT 
    else 
    inherited; 
end; 

var 
    TClientPanel_Registered: Boolean = False; 

constructor TMainPanel.Create(AOwner: TComponent); 
begin 
    inherited Create(AOwner); 
    FClient := TClientPanel.Create(Self); 
    FClient.Parent := Self; 
    FClient.Align := alClient; 
    Exclude(FComponentStyle, csInheritable); 
    if not TClientPanel_Registered then 
    begin 
    RegisterClasses([TClientPanel]); 
    TClientPanel_Registered := True; 
    end; 
end; 

destructor TMainPanel.Destroy; 
begin 
    FClient.Free; 
    inherited Destroy; 
end; 

function TMainPanel.GetChildOwner: TComponent; 
begin 
    Result := Self; 
end; 

procedure TMainPanel.GetChildren(Proc: TGetChildProc; Root: TComponent); 
begin 
    Proc(TControl(FClient)); 
end; 

procedure TMainPanel.CreateComponentEvent(Reader: TReader; ComponentClass: TComponentClass; var Component: TComponent); 
begin 
    if ComponentClass.ClassName = 'TClientPanel' then Component := FClient; 
end; 

procedure TMainPanel.ReadState(Reader: TReader); 
begin 
    Reader.OnCreateComponent := CreateComponentEvent; 
    inherited ReadState(Reader); 
    Reader.OnCreateComponent := nil; 
end; 

不是很专业,但我希望这将有助于:^)

附:只是做了一个快速测试(XE5),但基本上工作。

相关问题