Recent

Author Topic: [SOLVED] Cloning contents from a tabsheet into another one (not the hard way!)  (Read 29140 times)

Raul_ES

  • Full Member
  • ***
  • Posts: 183
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Cloning contents from a tabsheet into another one (not the hard way!)
« Reply #15 on: July 12, 2017, 05:51:07 pm »
I managed to created my very own frames thanks to  you guys  :D

check this example code:

Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Cloning contents from a tabsheet into another one (not the hard way!)
« Reply #16 on: July 12, 2017, 06:13:31 pm »
looks logical. You do know that the name is only useful for the streaming mechanism right? if you do not plan to stream the contents of your frame then leaving the name empty will work as well. There are a number of tricks you can do also, for example

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  9.   StdCtrls, Grids, Unit2;
  10.  
  11. type
  12.  
  13.   { TTabSheetFrame }
  14.  
  15.   TTabSheetFrame = class(TTabSheet)
  16.   private
  17.     FMyFrame: TFrame1;
  18.     procedure SetMyFrame(aValue: TFrame1);
  19.   public
  20.     constructor Create(TheOwner: TComponent); override;
  21.     property MyFrame : TFrame1 read FMyFrame;
  22.   end;
  23.  
  24.   { TForm1 }
  25.  
  26.   TForm1 = class(TForm)
  27.     Button1: TButton;
  28.     Button2: TButton;
  29.     Label2: TLabel;
  30.     PageControl1: TPageControl;
  31.     StringGrid1: TStringGrid;
  32.     procedure Button1Click(Sender: TObject);
  33.     procedure Button2Click(Sender: TObject);
  34.   private
  35.  
  36.   public
  37.  
  38.   end;
  39.  
  40. var
  41.   Form1: TForm1;
  42.  
  43. implementation
  44.  
  45. {$R *.lfm}
  46.  
  47. { TForm1 }
  48.  
  49. procedure TForm1.Button2Click(Sender: TObject);
  50. begin
  51.    Form1.Close;
  52. end;
  53.  
  54. procedure TForm1.Button1Click(Sender: TObject);
  55. var
  56.     k: integer;
  57.     lNewTabSheet: TTabSheet;
  58.     lNewFrame: TFrame1;
  59. begin
  60.     k := PageControl1.PageCount + 1;
  61.     if k <= 5 then
  62.       begin
  63.         lNewTabSheet := TTabSheetFrame.Create(PageControl1);
  64.         lNewTabSheet.PageControl := PageControl1;
  65.         with lNewTabSheet do
  66.           begin
  67.             Name := 'tab' + IntToStr(k);
  68.             Caption := 'Operation #' + IntToStr(k);
  69.           end;
  70. end;
  71.  
  72. { TTabSheetFrame }
  73.  
  74. constructor TTabSheetFrame.Create(TheOwner: TComponent);
  75. begin
  76.   inherited Create(TheOwner);
  77.   FMyFrame:=TFrame1.Create(TheOwner{or Self});
  78.   FMyFrame.Parent := Self;
  79.   FMYFrame.Align := alClient;
  80. end;
  81.  
  82.  
  83. end.
  84.  
  85.  
single creation for both ttabsheet and frame.

And of course the most unexpected.
Code: Pascal  [Select][+][-]
  1. { TTabSheetFrame }
  2.  
  3. constructor TTabSheetFrame.Create(TheOwner: TComponent);
  4. begin
  5.   FMyFrame:=TFrame1.Create(TheOwner);
  6.   inherited Create(FMyFrame);
  7.   FMyFrame.Parent := Self;
  8.   FMYFrame.Align := alClient;
  9. end;
  10.  
Now when you call
Code: Pascal  [Select][+][-]
  1.    TTabSheetFrame(PageControl1.Page[0]).MyFRame.Free;
  2.  
it will automatically destroy the TTabsheet too. Well This one needs testing I'm not comfortable using in production code but it shows how the owner mechanism works.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Raul_ES

  • Full Member
  • ***
  • Posts: 183
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Cloning contents from a tabsheet into another one (not the hard way!)
« Reply #17 on: July 12, 2017, 07:35:08 pm »
Ok. This is getting more complex...I think I'm going to blow a circuit in my brain. How to manage procedures and properties between the frame and the owner.

Code: Pascal  [Select][+][-]
  1. procedure TFrame1.BitBtn2Click(Sender: TObject);
  2. begin
  3.   // implement close active tabsheet method
  4.  
  5.   // Change the caption of the window (or a label or whatever) to say that
  6.   // tab number x has been deleted.
  7.    Form1.Caption := 'Deleting tab ' + InttoStr(PageControl1.ActivePageIndex);
  8.  
  9.    // delete the tabsheet
  10.    PageControl1.Page[PageControl1.ActivePageIndex].Destroy;
  11.  
  12. end;
  13.  

This code belongs to Unit2, the frame code. It gives the obvious error that Form1 and PageControl1 have not been declared (they belong to Unit1, the Form control). What I am doing wrong?
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Raul_ES

  • Full Member
  • ***
  • Posts: 183
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Cloning contents from a tabsheet into another one (not the hard way!)
« Reply #18 on: July 12, 2017, 07:37:49 pm »
Thanks taazz, I'm going to experiment with your code! Now I think I need a break...
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Cloning contents from a tabsheet into another one (not the hard way!)
« Reply #19 on: July 12, 2017, 07:51:05 pm »
Thanks taazz, I'm going to experiment with your code! Now I think I need a break...
erm let it be for now its a bit ahead still sorry.
Ok. This is getting more complex...I think I'm going to blow a circuit in my brain. How to manage procedures and properties between the frame and the owner.

Code: Pascal  [Select][+][-]
  1. procedure TFrame1.BitBtn2Click(Sender: TObject);
  2. begin
  3.   // implement close active tabsheet method
  4.  
  5.   // Change the caption of the window (or a label or whatever) to say that
  6.   // tab number x has been deleted.
  7.    Form1.Caption := 'Deleting tab ' + InttoStr(PageControl1.ActivePageIndex);
  8.  
  9.    // delete the tabsheet
  10.    PageControl1.Page[PageControl1.ActivePageIndex].Destroy;
  11.  
  12. end;
  13.  

This code belongs to Unit2, the frame code. It gives the obvious error that Form1 and PageControl1 have not been declared (they belong to Unit1, the Form control). What I am doing wrong?
where did you wrote this code? the frame? how about going on the form selecting the button inside the frame you have there and adding a new event for the buttons click (double the button for short).
Then write the code there. Keep in mind that the button's event inside the form will not automatically link when creating the frame dynamically you need to do it manually something along the lines of
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  9.   StdCtrls, Grids, Unit2;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     Button2: TButton;
  18.     Label2: TLabel;
  19.     PageControl1: TPageControl;
  20.     StringGrid1: TStringGrid;
  21.     procedure Button1Click(Sender: TObject);
  22.     procedure Button2Click(Sender: TObject);
  23.   private
  24.  
  25.   public
  26.     procedure FrameButton2Click(Sender:TObject);
  27.  
  28.   end;
  29.  
  30. var
  31.   Form1: TForm1;
  32.  
  33. implementation
  34.  
  35. {$R *.lfm}
  36.  
  37. { TForm1 }
  38.  
  39. procedure TForm1.FrameButton2Click(Sender:TObject);
  40. begin
  41.   Caption := 'Deleting tab ' + InttoStr(PageControl1.ActivePageIndex);
  42.   PageControl1.Page[PageControl1.ActivePageIndex].Destroy;
  43. end;
  44.  
  45. procedure TForm1.Button2Click(Sender: TObject);
  46. begin
  47.    Form1.Close;
  48. end;
  49.  
  50. procedure TForm1.Button1Click(Sender: TObject);
  51. var
  52.     k: integer;
  53.     lNewTabSheet: TTabSheet;
  54.     lNewFrame: TFrame1;
  55. begin
  56.     k := PageControl1.PageCount + 1;
  57.     if k <= 5 then
  58.       begin
  59.         lNewTabSheet := PageControl1.AddTabSheet;
  60.         with lNewTabSheet do
  61.           begin
  62.             Name := 'tab' + IntToStr(k);
  63.             Caption := 'Operation #' + IntToStr(k);
  64.           end;
  65.  
  66.         lNewFrame := TFrame1.Create(Form1);
  67.         with lNewFrame do
  68.           begin
  69.             Name := 'Frame' + IntToStr(k+1);  // <--- Here
  70.             Parent := lNewTabSheet;
  71.             Align := alClient;
  72.             BitBtn2.click := @framebutton2Click;
  73.           end;
  74.       end;
  75. end;
  76.  
  77. end.
  78.  
  79.  
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Raul_ES

  • Full Member
  • ***
  • Posts: 183
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Cloning contents from a tabsheet into another one (not the hard way!)
« Reply #20 on: July 12, 2017, 11:56:26 pm »
Thank you taazz.

Actually, is the Lazarus IDE itself that places the procedure TFrame1.BitBtn2Click(Sender: TObject) inside the frame source code file, not in the Form1, when double-clicking on the designer. So I thought that's the place should be. It would be possible to achieve the same using this approach instead?


And excuse my dummy question, In this piece of code:

Code: Pascal  [Select][+][-]
  1. BitBtn2.click := @framebutton2Click;

What does the @ mean? it has something to do with @override?


thanks!
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Cloning contents from a tabsheet into another one (not the hard way!)
« Reply #21 on: July 13, 2017, 03:50:47 am »
Thank you taazz.

Actually, is the Lazarus IDE itself that places the procedure TFrame1.BitBtn2Click(Sender: TObject) inside the frame source code file, not in the Form1, when double-clicking on the designer. So I thought that's the place should be. It would be possible to achieve the same using this approach instead?
Yes. a frame should be seen as a single entity what ever you write in there should only be about the frame it self,  behavior rules etc that cavern the controls and their interaction with each other nothing more.
And excuse my dummy question, In this piece of code:
Code: Pascal  [Select][+][-]
  1. BitBtn2.click := @framebutton2Click;

What does the @ mean? it has something to do with @override?
it is a way to instruct the compiler that you do not want to execute the method and assign the results but you want to assign the method it self as a value to the event.
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

jc99

  • Hero Member
  • *****
  • Posts: 553
    • My private Site
Re: Cloning contents from a tabsheet into another one (not the hard way!)
« Reply #22 on: July 15, 2017, 02:06:54 am »
And excuse my dummy question, In this piece of code:

Code: Pascal  [Select][+][-]
  1. BitBtn2.click := @framebutton2Click;

What does the @ mean? it has something to do with @override?

The @-operator generally gives you the address/reference of something instead of the object/variable.
The opposite operator is the ^-dereferencing operator that takes a (typed) address(pointer) and gives you the value.
example:
Code: Pascal  [Select][+][-]
  1.  
  2. var i:integer;
  3.      p:^integer; // p is declared as a pointer to integer;
  4.                        // normally pointer-variables are 'p'-prefixed
  5. begin
  6.    i := 5;    // This initializes the variable i
  7.    p := @i;   // This sets p to the address of i
  8.    i := 6;    // Now as a test you change i to 6
  9.    write(p^); // Surprise: This writes 6 and not 5
  10.    p^ := 7;   // Here you set the dereferenced address to 7
  11.    write(i);  // This will output the 7
  12. end;
  13.  
I hope this clarifies something ...
« Last Edit: July 15, 2017, 02:09:24 am by jc99 »
OS: Win XP x64, Win 7, Win 7 x64, Win 10, Win 10 x64, Suse Linux 13.2
Laz: 1.4 - 1.8.4, 2.0
https://github.com/joecare99/public
'~|    /''
,_|oe \_,are
If you want to do something for the environment: Twitter: #reduceCO2 or
https://www.betterplace.me/klimawandel-stoppen-co-ueber-preis-reduzieren

Raul_ES

  • Full Member
  • ***
  • Posts: 183
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Re: Cloning contents from a tabsheet into another one (not the hard way!)
« Reply #23 on: July 19, 2017, 06:05:41 pm »
Thanks Joe!
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Raul_ES

  • Full Member
  • ***
  • Posts: 183
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Hi,

I'm still working in this same small example. See attached files please.

There's something wrong here or maybe there is something I am missing. No clue:

Code: Pascal  [Select][+][-]
  1. BitBtn2.click := @framebutton2Click;

Compiler complains with an error message: Error: Argument cannot be assigned to

 %)
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
I think it should be:
Code: Pascal  [Select][+][-]
  1. BitBtn2.OnClick := @framebutton2Click;

Raul_ES

  • Full Member
  • ***
  • Posts: 183
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Thanks Handoko!

You are right, now it seems to work. I attach the updates an a minor fix.

regards,

Code: Pascal  [Select][+][-]
  1. unit Unit2;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, StdCtrls, ExtCtrls, Buttons;
  9.  
  10. type
  11.  
  12.   { TFrame1 }
  13.  
  14.   TFrame1 = class(TFrame)
  15.     BitBtn1: TBitBtn;
  16.     BitBtn2: TBitBtn;
  17.     BitBtn3: TBitBtn;
  18.     BitBtn4: TBitBtn;
  19.     BitBtn5: TBitBtn;
  20.     BitBtn6: TBitBtn;
  21.     BitBtn7: TBitBtn;
  22.     CheckBox1: TCheckBox;
  23.     Edit1: TEdit;
  24.     Edit2: TEdit;
  25.     Edit3: TEdit;
  26.     Edit4: TEdit;
  27.     GroupBox1: TGroupBox;
  28.     Label1: TLabel;
  29.     Label2: TLabel;
  30.     Label3: TLabel;
  31.     Label4: TLabel;
  32.     Label5: TLabel;
  33.     Panel1: TPanel;
  34.     StaticText1: TStaticText;
  35.     procedure BitBtn1Click(Sender: TObject);
  36.     procedure BitBtn2Click(Sender: TObject); // don't remove
  37.     procedure BitBtn3Click(Sender: TObject);
  38.     procedure BitBtn4Click(Sender: TObject);
  39.     procedure BitBtn5Click(Sender: TObject);
  40.     procedure BitBtn6Click(Sender: TObject);
  41.     procedure BitBtn7Click(Sender: TObject);
  42.   private
  43.  
  44.   public
  45.  
  46.   end;
  47.  
  48. implementation
  49.  
  50. {$R *.lfm}
  51.  
  52. { TFrame1 }
  53.  
  54. procedure TFrame1.BitBtn2Click(Sender: TObject); // don't remove
  55. begin
  56.   // implement close active tabsheet method
  57.  
  58.   //PageControl1.Page[PageControl1.ActivePageIndex].Destroy; ----> implemented in Form1 code
  59.  
  60. end;
  61.  
  62. procedure TFrame1.BitBtn3Click(Sender: TObject);
  63. begin
  64.   Label3.caption := 'Suma';
  65. end;
  66.  
  67. procedure TFrame1.BitBtn4Click(Sender: TObject);
  68. begin
  69.   Label3.caption := 'Resta';
  70. end;
  71.  
  72. procedure TFrame1.BitBtn5Click(Sender: TObject);
  73. begin
  74.   Label3.caption := 'División';
  75. end;
  76.  
  77. procedure TFrame1.BitBtn6Click(Sender: TObject);
  78. begin
  79.   Label3.caption := 'Multiplicación';
  80. end;
  81.  
  82. procedure TFrame1.BitBtn7Click(Sender: TObject);
  83. begin
  84.   // implement save result to log
  85.  
  86. end;
  87.  
  88. procedure TFrame1.BitBtn1Click(Sender: TObject);
  89. begin
  90.   // implement reset input values to zero
  91.  
  92. end;
  93.  
  94. end.

And the Form1 code:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  9.   StdCtrls, Grids, Unit2, Buttons;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     Button2: TButton;
  18.     Label2: TLabel;
  19.     PageControl1: TPageControl;
  20.     StringGrid1: TStringGrid;
  21.     procedure Button1Click(Sender: TObject);
  22.     procedure Button2Click(Sender: TObject);
  23.   private
  24.  
  25.   public
  26.     procedure Frame1BitBtn2Click(Sender: TObject);
  27.   end;
  28.  
  29. var
  30.   Form1: TForm1;
  31.  
  32. implementation
  33.  
  34. {$R *.lfm}
  35.  
  36. { TForm1 }
  37.  
  38. procedure TForm1.Button2Click(Sender: TObject);
  39. begin
  40.    Form1.Close;
  41. end;
  42.  
  43. ///////////////////////
  44.  
  45. procedure TForm1.Frame1BitBtn2Click(Sender: TObject);
  46. begin
  47.    PageControl1.Page[PageControl1.ActivePageIndex].Destroy;
  48. end;
  49.  
  50. ///////////////////////
  51.  
  52. procedure TForm1.Button1Click(Sender: TObject);
  53. var
  54.     k: integer;
  55.     lNewTabSheet: TTabSheet;
  56.     lNewFrame: TFrame1;
  57. begin
  58.     k := PageControl1.PageCount + 1;
  59.     if k <= 5 then
  60.       begin
  61.         lNewTabSheet := PageControl1.AddTabSheet;
  62.         with lNewTabSheet do
  63.           begin
  64.             Name := 'tab' + IntToStr(k);
  65.             Caption := 'Operation #' + IntToStr(k);
  66.           end;
  67.  
  68.         lNewFrame := TFrame1.Create(Form1);
  69.         with lNewFrame do
  70.           begin
  71.             Name := 'Frame' + IntToStr(k+1);  // <--- Here
  72.             Parent := lNewTabSheet;
  73.             Align := alClient;
  74.             //
  75.             BitBtn2.OnClick := @Frame1BitBtn2Click; //
  76.             // BitBtn2.Click ----> Error: Argument cannot be assigned to
  77.           end;
  78.       end;
  79. end;
  80.  
  81. end.
  82.  
« Last Edit: August 20, 2017, 04:41:40 pm by Raul_ES »
Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Raul_ES

  • Full Member
  • ***
  • Posts: 183
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
How can we verify from the Form1 code the value of a variable/checkbox from Frame1? defining a global public variable to store the value of interest? what approach would you recommend?

Check the following example:

In frame1 there's a checkbox that if true indicates that the results has been correctly stored or saved to a file.

In Form1 there's a Quit button that veryfies the status of this checkbox, and if not checked it doesn't allow the user to quit the program and displays a messagebox warning about the reason.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button2Click(Sender: TObject);
  2. begin
  3.  
  4.    if (CheckBox1.Checked = true) then    // this CheckBox1 is in Frame1. What's the best way to access it? a kind of Getter?
  5.    Form1.Close else ShowMessage('Save results before quitting.');
  6. end;
  7.  


Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

Handoko

  • Hero Member
  • *****
  • Posts: 5131
  • My goal: build my own game engine using Lazarus
You have to do:
1. Make lNewFrame a global variable 
2. In Button2Click, make sure the variable is assigned
3. Use lNewFrame.CheckBox1.Checked to access the value
4. Remove lNewFrame's variable declaration in Button1Click
5. And don't forget to free lNewFrame when no longer need it

Code: Pascal  [Select][+][-]
  1. // ....
  2. implementation
  3.  
  4. var
  5.   lNewFrame: TFrame1;
  6.  
  7. {$R *.lfm}
  8.  
  9. { TForm1 }
  10.  
  11. procedure TForm1.Button2Click(Sender: TObject);
  12. begin
  13.    if not(Assigned(lNewFrame)) then Exit;
  14.    if (lNewFrame.CheckBox1.Checked = true) then
  15.    Form1.Close else ShowMessage('Save results before quitting.');
  16. end;
« Last Edit: August 20, 2017, 06:28:48 pm by Handoko »

Raul_ES

  • Full Member
  • ***
  • Posts: 183
  • My interests: Healthcare & Computers
    • My Linkedin Profile, you can add me to stay in contact.
Thank you again Handoko :-)

Just a point: I thought that the frame was automathicaly freed when closing it's parent control (form1). Am I wrong?


regards

Pharmacy + Chemistry + Biology + Healthcare + Computing

If you have any interest or project related with these areas feel free to contact me!

 

TinyPortal © 2005-2018