2010-04-19 50 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),但基本上工作。

相關問題