Trouble with TFrames lazarus / 31-LCL ---------------------------------------------------------------------- andyH · 2022-02-09 17:32 Running under linux with GTK2 if relevant. I have a simple form with a number of tabs on it. I'm using a TPanel as a container on each tab. In the real application, each TPanel is a child of the base class with its own methods. The sample project attached only has a TPanel on the first tab. It works, see screenshot. I'm trying to replace the TPanel with a TFrame as the container and failing. The sample project attached only has a TPanel or TFrame on tab 1. This is the unit for the panel: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i unit basepanel; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, StdCtrls, Controls, CheckLst, ExtCtrls, Graphics, Dialogs, LCLtype; type   TBasePanel = class(TPanel)  const    phBottom = 68;  phBorder = 10;    pwBorder = 15;  protected    BoxItemHeight : integer;    TitleLbl : TLabel;    Box1 : TCheckListBox;    NextBtn : TButton;  public    constructor Create(TheOwner: TComponent);  end;var  TestTab : TBasePanel; implementation constructor TBasePanel.Create(TheOwner: TComponent);var  BoxHeight, BoxWidth : integer;  i : byte;begin  BoxHeight:= 100;  BoxWidth:= 200;   inherited Create(TheOwner);  // Title label  TitleLbl:= TLabel.Create(Self);  with TitleLbl do begin       Parent:= self;     AnchorSide[akTop].Side:= asrTop;       AnchorSide[akTop].Control:= self;       BorderSpacing.top:= phBorder * 2;       AnchorSide[akLeft].Side:= asrLeft;       AnchorSide[akLeft].Control:= self;       BorderSpacing.left:= pwBorder;       Caption:= 'A checklistbox on panel';  end;  // check box 1  Box1:= TCheckListBox.Create(Self);  with Box1 do begin       Parent:= self;     AnchorSide[akTop].Side:= asrBottom;       AnchorSide[akTop].Control:= TitleLbl;       BorderSpacing.top:= phBorder;       AnchorSide[akLeft].Side:= asrLeft;       AnchorSide[akLeft].Control:= TitleLbl;       BorderSpacing.left:= 0;       Width:= BoxWidth;       Height:= BoxHeight;       for i:= 0 to 5 do Items.Add('An item in box ' + inttostr(i));  end;  // Next button  NextBtn:= TButton.Create(Self);  with NextBtn do begin       Parent:= self;       Caption:= 'Button on panel';       AnchorSide[akTop].Side:= asrBottom;       AnchorSide[akTop].Control:= Box1;       BorderSpacing.top:= 10;       AnchorSide[akLeft].Side:= asrLeft;       AnchorSide[akLeft].Control:= self;       BorderSpacing.left:= 10;       Width:= 120;  end;end;end.       Change TPanel to TFrame in the type definition. It compiles. Runtime error: QuoteResource TBasePanel not foundGoogle, and https://wiki.freepascal.org/Frames says QuoteTFrame does not have OnCreate or OnDestroy events in which private variables can be initialised and released. Override the default constructor and destructor to do this.Change the type definition for the constructor to include override - no change, same error message. Take a clue from the error message, file > new > select Tframe. Now I have a lfm file for the unit. Copy code for the TPanel over and modify keeping the compiler directive {$R *.lfm}. Compiles - same runtime error message. QuoteResource TBaseFrame not found Googling has not come up with anything useful. Sample project attached. unit1 is the main form and basepanel & baseframe the units for either a TPanel or TFrame container. I've been testing by commenting in/out in unit1. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   //TestTab:= TBasePanel.Create(self);  TestFrame:= TBaseFrame.Create(self);  //with TestTab do  with TestFrame do      begin        Anchors:=[akLeft,akTop,akRight,akBottom];         Parent:= PageCtrl.Page[0];        Width:= Parent.ClientWidth;        Height:= Parent.ClientHeight;      end;As supplied it is set up for a TFrame. ---------------------------------------------------------------------- engkin · 2022-02-09 18:21 BaseFrame.lfm is: Quoteobject Frame1: TFrame1   Left = 0   Height = 240   Top = 0   Width = 320   TabOrder = 0   DesignLeft = 200   DesignTop = 151 end Do you see TBaseFrame here? Me neither. ---------------------------------------------------------------------- mas steindorff · 2022-02-09 19:53 Quote from: andyH on February 09, 2022, 06:32:50 pmI'm trying to replace the TPanel with a TFrame as the container and failing. The sample project attached only has a TPanel or TFrame on tab 1. why replace? I always use a Tpanel as the parent for the TFrame.  That way the destroy code is automatic as parents handle their children... If it's a matter of fit, here is what I do in my FormCreate: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var AccFram :TFram_3d_Data; procedure TFrmAccelDiag.FormCreate(Sender: TObject);begin  AccFram := TFram_3D_Data.Create(PanAcc); // will auto free  AccFram.Parent := PanAcc;          // this panel already exist.  I do not know if this line is needed now days   AccFram.Align  := alClient;          // fill the panal  ...end; and we are done.  the  Tframe's ".free " is automatically handled. Mas ---------------------------------------------------------------------- andyH · 2022-02-09 20:16 @engkin - Thanks for rapid reply and pointer. Got me going in the right direction. Well that worked. Started again. Instead of just adding a new unit and rather than copy/paste code I selectively pasted my original code. File > new > TFrame. Did not change any of the 'defaults', so I have a  TFrame2 = class(TFrame) not TBaseFrame = class(TFrame)unit2 (so unit2.pas not baseframe.pas) and a corresponding unit2.lfm with contentCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i object Frame2: TFrame2  Left = 0  Height = 240  Top = 0  Width = 320  TabOrder = 0  DesignLeft = 200  DesignTop = 151end   But confused. Note, I do not use the forms designer, I do everything in code. If I change TFrame2 = class(TFrame) to TBaseFrame = class(TFrame) will this be reflected in the lfm file and work? I can try this myself. Why do I need an lfm file for a TFrame but not a TPanel? What is the problem with the lfm file because if I look at the lfm file for unit1 (the main form), content is:Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i object Form1: TForm1  Left = 200  Height = 240  Top = 151  Width = 320  Caption = 'Form1'  LCLVersion = '2.0.10.0'end yet in unit1, the definition is TMainFm = class(TForm) and the variable is declared as  MainFm : TMainFm, no Form1 or TForm1. I have changed the main project file so it is Application.CreateForm(TMainFM, MainFm); While I have it working, I'm trying to understand why it didn't work and what I might have to do when I create descendents, e.g. TChildFrame = class(TBaseFrame)? @mas steindorff - why am I doing this as it works with a TPanel: https://forum.lazarus.freepascal.org/index.php/topic,57918.msg431304.h tml#msg431304 The writing is on the wall for GTK2 and I am hoping that TFrame + qt renders correctly. ---------------------------------------------------------------------- howardpc · 2022-02-09 23:38 Quote from: andyH on February 09, 2022, 09:16:11 pmWhy do I need an lfm file for a TFrame but not a TPanel?Because frames are designed specifically to need a resource, and their constructor checks for a resource somewhere in their ancestry and gives you the "Resource xxx not found" message you have received when trying to construct a frame without any .lfm resource. Frames differ from forms here, because you can construct a resourceless form using the TForm.CreateNew() constructor. However this restriction on frames is very slight. You can create a frame named TBaseFrame via File > New... > Frame, adding nothing to it at all in a simple skeleton unit with just a minimal handful of lines, and naming it, say uBaseFrame.pas. Then using uBaseFrame in the uses clause of a different unit, you can construct any descendant of TBaseFrame you want, with whatever components, methods and properties you wish to add to the descendent frame, all in code. So long as a frame has an .lfm resource somewhere in its ancestry, the LCL is happy. ---------------------------------------------------------------------- andyH · 2022-02-10 15:18 @howardpc thanks for the explanation. Now have a better understanding of TFrames and was able to get my sample project with a TFrame working, see screenshot. However, it didn't solve the root problem I was trying to fix. Recompiled for qt5 - second screenshot. Same behaviour I get with a TPanel. I had hoped for better. Back to the drawing board, I need a better understanding of how qt5 works for lazarus.