Icon View Thread

The following is the text of the current message along with any replies.
Messages 1 to 4 of 4 total
Thread Trouble trying to embedd control... confused.
Tue, Jul 19 2016 5:41 PMPermanent Link

Mario Enríquez

Open Consult

Hi everybody,

I having trouble embedding a control into another one. Think TGrid and TGridColumns...

I wrote a TTablero control that should have TBahia sub controls.

Everything is fine until the AgregarBahia method on TTablero is called. The method is supposed to add a TBahia control and show it inside another TElement on TTablero. The code is the following:

procedure TTablero.AgregarBahia(Codigo, Etiqueta: string);
var
  bahia: TBahia;
begin            
  bahia := TBahia.Create(FBahias);
  
  if bahia <> nil then
     bahia.Visible := True;
end;

When this method is invoked I get the following error:

"Unable to get property 'telement_setvisible' of undefined or null reference"

It seems like I'm trying to invoke a method in a null reference of TElement, however I should have been created in its ancestor method, correct? .. I'm confused...

Here's the code if you would like to get the time to check it out...


  TBahia = class(TControl)
     private
        FParent: TElement;
        FCodigo: TElement;
        { Private declarations }

        function GetBorder: TBorder;
        function GetCorners: TCorners;
        function GetFill: TFill;

        function GetCodigo: string;
        procedure SetCodigo(ACodigo: string);

        function GetVisible: boolean;
        procedure SetVisible(AValue: boolean);
     protected
        procedure InitializeProperties; override;
        function GetInterfaceName: string;
        procedure CreateInterfaceElements; override;

     public
        property Codigo: string read GetCodigo write SetCodigo;
           
        constructor Create(APadre: TElement);

        property Top;
        property Left;
        property Height;
        property Width;
        property Border: TBorder read GetBorder;
        property Constraints;
        property Corners: TCorners read GetCorners;
        property Cursor;
        property DisplayOrder;
        property Fill: TFill read GetFill;
        property Layout;
        property LayoutOrder;
        property Margins;
        property Visible : boolean read GetVisible write SetVisible;
  end;

  {$INTERFACE TTablero}

  TTablero = class(TControl)
     private
        FHorario: TElement;
        FBahias: TElement;
        
        { Private declarations }

        function GetBorder: TBorder;
        function GetCorners: TCorners;
        function GetFill: TFill;
     protected
        { Protected declarations }
        property HorarioElement: TElement read FHorario;
        property BahiasElement: TElement read FBahias;

        procedure InitializeProperties; override;
        function GetInterfaceName: string;
        procedure CreateInterfaceElements; override;
     public
        { Public declarations }
        
        procedure AgregarBahia(Codigo, Etiqueta: string);
     published
        { Published declarations }
        property Top;
        property Left;
        property Height;
        property Width;
        property Border: TBorder read GetBorder;
        property Constraints;
        property Corners: TCorners read GetCorners;
        property Cursor;
        property DisplayOrder;
        property Fill: TFill read GetFill;
        property Layout;
        property LayoutOrder;
        property Margins;
        property Visible;
     end;


implementation

{ TBahia }

constructor TBahia.Create(APadre: TElement);
begin              
  inherited Create;

  FParent := APadre;
  CreateInterfaceElements;
end;

function TBahia.GetVisible: boolean;
begin
  Result := Element.Visible;
end;

procedure TBahia.SetVisible(AValue: boolean);
begin
  Element.Visible := AValue;
end;


procedure TBahia.InitializeProperties;
begin
  inherited InitializeProperties;
  InterfaceState := NORMAL_STATE_NAME;
end;

function TBahia.GetInterfaceName: string;
begin
  Result := TBahia.ClassName;
end;

procedure TBahia.CreateInterfaceElements;
begin                                     
  inherited CreateInterfaceElements;
  
  FCodigo := InterfaceManager.CreateElement(CODIGO_BAHIA_ELEMENT_NAME, Element, ELEMENT_CLASS_DIV);
end;


{ TTablero }
procedure TTablero.AgregarBahia(Codigo, Etiqueta: string);
var
  bahia: TBahia;
begin            
  bahia := TBahia.Create(FBahias);
  
  if bahia <> nil then
     bahia.Visible := True;
end;

procedure TTablero.InitializeProperties;
begin
  inherited InitializeProperties;
  InterfaceState := NORMAL_STATE_NAME;
end;

function TTablero.GetInterfaceName: string;
begin
  Result := TTablero.ClassName;
end;

procedure TTablero.CreateInterfaceElements;
begin                                     
  inherited CreateInterfaceElements;

  FBahias := InterfaceManager.CreateElement(BAHIAS_ELEMENT_NAME, Element, ELEMENT_CLASS_DIV);

end;


Thank you!
Mario
Wed, Jul 20 2016 11:35 AMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

Mario,

Your TBahia constructor isn't correct.  You should override the TControl constructor, not define your own:

constructor TBahia.Create(AOwner: TComponent);
begin              
 inherited Create(AOwner);
end;

However, you don't actually need to do that in this case, and can skip the constructor altogether.  Instead, just validate the owner class in the InitializeProperties method:

procedure TBahia.InitializeProperties;
begin
 inherited InitializeProperties;
 CheckOwnerClass(TTablero);
 InterfaceState := NORMAL_STATE_NAME;
end;

The TControl class will automatically handle parenting the TBahia control to the ClientElement of the owner TControl (in this case, the TTablero instance).  By default, the ClientElement property refers to the base Element property of any TControl instance.  However, certain classes like the TPanel class have actual client elements that act as the container for child controls, and override the protected GetClientElement method to return the child client element instead of the default outer base element. But, as long as you refer to the ClientElement property, these details are transparent to you and you don't need to worry about them.

You also don't need to track the parent's client element - you can always get it by just using this code:

MyControl.Parent.ClientElement

Finally, when creating the TBahia instances, do it like this:

procedure TTablero.AgregarBahia(Codigo, Etiqueta: string);
var
 bahia: TBahia;
begin            
 bahia := TBahia.Create(Self);
 
 if bahia <> nil then
    bahia.Visible := True;
end;

Tim Young
Elevate Software
www.elevatesoft.com
Wed, Jul 20 2016 11:16 PMPermanent Link

Mario Enríquez

Open Consult

Thank you Tim, is working now.

What if I want to show the TBahia control inside a TElement other that ClientElement on the parent? Is there way to accomplish this?

Regards,
Mario
Fri, Jul 22 2016 10:45 AMPermanent Link

Tim Young [Elevate Software]

Elevate Software, Inc.

Avatar

Email timyoung@elevatesoft.com

Mario,

<< What if I want to show the TBahia control inside a TElement other that ClientElement on the parent? Is there way to accomplish this? >>

Yes, override this protected method for the parent control:

        procedure AddControlElement(AControl: TControl); virtual;

By default, it looks like this:

procedure TControl.AddControlElement(AControl: TControl);
begin
  AControl.Element.Parent:=ClientElement;
end;

If you do override this method, then be sure to *not* call the inherited method from the TControl class.

Tim Young
Elevate Software
www.elevatesoft.com
Image