Reputation: 101
I have a very simple Firemonkey project (RadStudio 10.3.3) that I am building to test certain layout options for a future project. In the past with VCL, I used modal forms. The project I am testing uses panels (Panel1 and Panel2) on the main form (Form1) to embed two additional forms (Form2 and Form3). The two embedded forms consist of a single listbox (ListBox1) on each form. The panels on the main form overlay, so I use the Visibility property to show the embedded form that I want. All the code is on the main form.
The issue I have is that when I switch between Form2 and Form3, the strings loaded into the listbox on Form3 never appear. I have tried Repaint on the listbox and panel, InvalidateRect on the listbox, SetFocus on the panel, etc., all followed by Application.ProcessMessages. Nothing works successfully.
The main code is:
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
Panel2: TPanel;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
procedure EmbedForm(AParent:TControl; AForm:TCustomForm);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
uses Unit2, Unit3;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Embed Form2 in Panel1
Application.CreateForm(TForm2, Form2);
EmbedForm(Panel1, Form2);
Panel1.Visible := true;
// Embed Form3 in Panel2
Application.CreateForm(TForm3, Form3);
EmbedForm(Panel2, Form3);
Panel2.Visible := false;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
// Populate ListBox1 on Form2 - the LOAD button
Form2.ListBox1.Items.Add('Hello');
Form2.ListBox1.Items.Add('World');
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
// Hide Panel1 (Form2) and show Panel2 (Form3)
Panel1.Visible := false;
Panel2.Visible := true;
// Populate ListBox1 on Form3
Form3.ListBox1.Items.Add('Goodbye');
Form3.ListBox1.Items.Add('World');
// Repaint (Here's why I have tried various things to get the listbox strings to show up)
//Panel2.Repaint;
//Form3.ListBox1.Repaint;
//Application.ProcessMessages;
end;
procedure TForm1.EmbedForm(AParent: TControl; AForm: TCustomForm);
begin
while AForm.ChildrenCount>0 do
AForm.Children[0].Parent:=AParent;
end;
end.
Form2 is as follows:
unit Unit2;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts,
FMX.ListBox;
type
TForm2 = class(TForm)
ListBox1: TListBox;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form2: TForm2;
implementation
{$R *.fmx}
end.
Form3 is as follows:
unit Unit3;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Layouts,
FMX.ListBox, FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm3 = class(TForm)
ListBox1: TListBox;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form3: TForm3;
implementation
{$R *.fmx}
end.
The .fmx files are below, as requested.
Unit1.fmx (Form1):
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 480
ClientWidth = 640
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
OnCreate = FormCreate
DesignerMasterStyle = 0
object Button1: TButton
Position.X = 232.000000000000000000
Position.Y = 448.000000000000000000
TabOrder = 1
Text = 'Load'
OnClick = Button1Click
end
object Button2: TButton
Position.X = 328.000000000000000000
Position.Y = 448.000000000000000000
TabOrder = 2
Text = 'Next'
OnClick = Button2Click
end
object Panel1: TPanel
Align = Center
Size.Width = 640.000000000000000000
Size.Height = 393.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
end
object Panel2: TPanel
Position.Y = 43.000000000000000000
Size.Width = 640.000000000000000000
Size.Height = 393.000000000000000000
Size.PlatformDefault = False
TabOrder = 4
end
end
Unit2.fmx (Form2):
object Form2: TForm2
Left = 0
Top = 0
Caption = 'Form2'
ClientHeight = 480
ClientWidth = 640
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
DesignerMasterStyle = 0
object ListBox1: TListBox
Align = Center
TabOrder = 0
DisableFocusEffect = True
DefaultItemStyles.ItemStyle = ''
DefaultItemStyles.GroupHeaderStyle = ''
DefaultItemStyles.GroupFooterStyle = ''
Viewport.Width = 200.000000000000000000
Viewport.Height = 200.000000000000000000
end
end
Unit3.fmx (Form3):
object Form3: TForm3
Left = 0
Top = 0
Caption = 'Form3'
ClientHeight = 480
ClientWidth = 640
FormFactor.Width = 320
FormFactor.Height = 480
FormFactor.Devices = [Desktop]
DesignerMasterStyle = 0
object ListBox1: TListBox
Position.X = 8.000000000000000000
Position.Y = 8.000000000000000000
TabOrder = 1
DisableFocusEffect = True
DefaultItemStyles.ItemStyle = ''
DefaultItemStyles.GroupHeaderStyle = ''
DefaultItemStyles.GroupFooterStyle = ''
Viewport.Width = 196.000000000000000000
Viewport.Height = 196.000000000000000000
end
end
Again, Form2 and Form3 each only contain a listbox (Listbox1 on both) and no additional code. I simply run the executable, click Button1 to display Hello World, then click Button2 to switch panels and display the second form and its listbox. As I am new to Firemonkey, I am sure I am missing something simple. Thanks for any and all help!
The solution was very simple. I had to remove the CreateForm events for Form2 and Form3 from the project's initialization settings--a dumb mistake on my part. It was losing the reference to those forms during execution.
Upvotes: 1
Views: 950
Reputation: 101
Ok, thanks to Tom's frustration (again, I am sorry Tom!) and my own, I rebuilt the test application once again. This time, neither listbox would show the strings. I then began thinking about Form2 and Form3 losing their connection to Form1, so I looked into the .fmx files that Tom had asked about. That led me to looking into the Project initialization file, and voila!
program Project1;
uses
System.StartUpCopy,
FMX.Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2},
Unit3 in 'Unit3.pas' {Form3};
{$R *.res}
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
//Application.CreateForm(TForm2, Form2); <-- NOW COMMENTED OUT
//Application.CreateForm(TForm3, Form3); <-- NOW COMMENTED OUT
Application.Run;
end.
The application was creating Form2 and Form2 on startup, and then I would create duplicates within the code, thus leading to a loss of reference. I simply commented out the Form2 and Form3 lines in startup to keep the application from creating them and it works as intended. Thanks, Tom!
Upvotes: 1
Reputation: 21045
The only way I can reproduce the error is by setting the parent - child relation between the form and the two panels wrong.
E.g. I can reproduce the erroneous behaviour you describe, if Panel2
is a child of Panel1
, but if they are both childs of the form, I can not reproduce the problem. Perhaps you dropped the second panel on Panel1
by mistake? Check the structure window in the IDE.
Edit after .fmx
files were added to the question
Looking at the supplied Unit1.fmx
which ends like this:
object Panel1: TPanel
Align = Center
Size.Width = 640.000000000000000000
Size.Height = 393.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
object Layout1: TLayout
Align = Contents
Size.Width = 640.000000000000000000
Size.Height = 393.000000000000000000
Size.PlatformDefault = False
TabOrder = 0
end
end
There is no Panel2
as there should be according to Unit1.pas
. Instead there is a Layout1
as child to Panel1
. So, the now posted .fmx
file doesn't match the .pas
file you supplied yesterday. But it might still confirm what I already said.
If Panel2
has been substituted with this layout, and in other words Panel2
was a child to Panel1
, then this would exactly explain the behaviour you asked about originally.
Upvotes: 1