开发者

Why the composite component fails to parent controls?

I created my own Component : TPage , which Contains Subcomponent TPaper (TPanel). The problem is, that when I put controls such as TMemo or TButton on the TPaper (which fills up nearly whole area), the controls do not load at all. see example below

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 is parented in TPaper (TPanel) at design-time, but after pressing "Run" it does not exist.

procedure TForm1.btn1Click(Sender: TObject);
begin
if not Assigned(Memo1) then Sho开发者_如何学PythonwMessage('I do not exist');   //Memo1 is nil
end;

Have you any idea what's wrong?

Thanks a lot

P.S Delphi 7

When I put TMemo inside TPaper and save the unit (Unit1), after inspection of associated dfm file, there is no trace of TMemo component. (Thats why it can not load to app.)


Serge is right. Delphi only streams components that are owned by the Form they reside in. In order to avoid the EClassNotfound Exception, which occurs during reading of the form file (You should now at least see a Tpaper component in your dfm file) you must register the class by using the RegisterClass function (in the unit Classes). A good place for this would be in the initialisation section of your unit.

If setting the owner of Tpaper to a Form is not an option, then you can still get Delphi to stream your subcomponents by overriding the Getchildren and GetChildOwner methods and applying the logic TCustomForm uses:

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;


The question is 5 years ago, but because I came across the same problem and could not find a workable solution in the network decided to share what I found as a solution after much testing.

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;

Not very professional, but I hope it will help :^)

P.S. just did a quick test (XE5), but basically works.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜