JohnLM 23 Posted Tuesday at 10:11 PM (edited) Specs: XE7, VCL, Win7 I have a Panel with a TabControl in it and a Memo inside the first TabSheet on a Form that was all created and configured during design time. And, on the Form in another Panel, I have a [Add] button to dynamically create a new TabSheet and Memo. The main Memo is the default with all the settings that I would like the dynamically created Memos to have. But setting up all the necessary properties would be tedious and if I change something in the main Memo at design-time, I may not remember to update that to the dynamic ones. var Form1: TForm1; idx: integer=0; // index numb, for adding new tabs to the pagecontrol. procedure TForm1.btnAddClick(Sender: TObject); var TabSheet: TTabSheet; memo: TMemo; begin inc(idx); TabSheet := TTabSheet.Create(PageControl1); TabSheet.Caption := 'Untitled-'+idx.ToString; TabSheet.PageControl := PageControl1; memo := tmemo.Create(pagecontrol1); // settings section memo.Color := $0017110D; memo.Align := alClient; . . . // end of settings section memo.Parent := tabsheet; memo.Show; memo.SetFocus; end; note: I have a lot more properties than what is posted above. Is there a better way to copy all the properties of the main Memo to the dynamically created ones and how can I do this? Edited Tuesday at 10:19 PM by JohnLM updated missing code fragment Share this post Link to post
Anders Melander 1819 Posted Tuesday at 11:30 PM 1 hour ago, JohnLM said: if I change something in the main Memo at design-time, I may not remember to update that to the dynamic ones. So don't set them at design-time; Set them at run-time in a function that will then also be used setup the other memos. There aren't that many properties on a TMemo so I really don't think it's worth it to try and be clever here but if you really want to you can either use RTTI or streaming (see TStream.WriteComponent/ReadComponent). If your memo use event handlers you will get into trouble with the stream method. Share this post Link to post
corneliusdavid 221 Posted Tuesday at 11:32 PM 1 hour ago, JohnLM said: Is there a better way to copy all the properties of the main Memo to the dynamically created ones and how can I do this? RTTI Share this post Link to post
Vincent Parrett 781 Posted Tuesday at 11:45 PM Keep it simple - create a class helper for TMemo and add an Assign method and just set the props you need. This will be quicker and easier than messing with RTTI (which can be a bit of a rabbit hole with some property types). 1 Share this post Link to post
Brandon Staggs 296 Posted Wednesday at 06:52 PM 19 hours ago, Vincent Parrett said: Keep it simple - create a class helper for TMemo and add an Assign method and just set the props you need. This will be quicker and easier than messing with RTTI (which can be a bit of a rabbit hole with some property types). This is the way. Share this post Link to post
JohnLM 23 Posted Friday at 10:21 PM Update on my progress. . . You guys can do this! I have no doubt! I know you all can figure this out, lickady-split or a few minutes, but I am not in your category. I am just a lowly hobbiest at best. Unfortunately, I am no component expert, nor am I am Pro at Pascal programming, let alone OOP and all. I am just a casual guy who codes small Windows utilities and other fun and interesting things. Occasionally I will try and learn OOP and component anything but I do not get very far, as I am a very slow learner. Anyway. I have looked into the suggestions here, and also my own searches. I found some resources and spent a great deal of time trying to understand them and then build them, but to no avail. I am just a complete failure in these advanced areas. For instance, in one resource (web search) I did find a routine that shows how to pull properties from all components on the form. And in another resource (web search) I found another routine showing how to pull properties similarly but slitely less detail. And yet in another resource showing similar, I can pull and narrow down to just tmemo's properties, which is just what I was looking for as a start. And then, in another resource, I found where I could: pull the properties of a tmemo and show it in another memo and make changes to the properties in that memo and the routine would show a memo with the changed state. But, I could not get it to copy from another memo, its properties because it would issue an error: "memo has no parent window" and other errors as well. I tried many scenarios of code ideas but to no avail. There is one more resource that I found (from the lazarus website) to try out, the next time I come back from a break from this endeavor. As for now and after three very long days and nights and many many hours, so many hours, of trying to figure this out, I am giving this up. I am taking a break and going back to other projects. Thank you all for your suggestions. Share this post Link to post
Remy Lebeau 1449 Posted Saturday at 03:10 AM (edited) On 1/7/2025 at 3:11 PM, JohnLM said: Is there a better way to copy all the properties of the main Memo to the dynamically created ones and how can I do this? Yes - don't make a copy at all! Use a TFrame instead. https://docwiki.embarcadero.com/RADStudio/en/Working_with_Frames At design-time, create a new TFrame class, put a TMemo on it, and configure it as needed. Then at runtime, you can create a new instance of your Frame class (which will have all of your design-time property values) and assign a Parent to it as needed. In this case, a new TabSheet. With this approach, you also won't need to waste a TabSheet at design-time just to hold your default values. But, if you really want to, you can place your Frame on the 1st TabSheet at design-time, too. Edited Saturday at 03:12 AM by Remy Lebeau Share this post Link to post
JohnLM 23 Posted Saturday at 11:42 AM Update on progress. . . continues. . . @Remy Lebeau, I have tried your suggestion. And after many hours, I finally got it working, I think. I never worked with Frames before. I still don't understand them but in this case, I do believe I have it working, but with a few slight issues. 1st, the code, now modified for Frame support: procedure TForm1.btnAddClick(Sender: TObject); var TabSheet: TTabSheet; mem: unit2.TFrame2; begin inc(idx); TabSheet := TTabSheet.Create(PageControl1); TabSheet.Caption := 'Untitled-'+idx.ToString; TabSheet.PageControl := PageControl1; mem := tframe2.Create(nil); mem.Parent := tabsheet; mem.Name := 'Untitled'+idx.ToString; mem.memo1.Align := alClient; mem.memo1.Show; mem.memo1.SetFocus; end; And the results: As for the issues: 1) all the tabs I create have the same name, "memo1". (see code) 2) the alignment to client is quirky, but I managed to get it to work to fill the tab area. (see code) 3) the memo's names (for each tab do not show up in the memo's view. They all say the same thing, "memo1". (see code) they should be "Untitled1, Untitled2, Untitled3, ..." in each memo, just like when you add a new memo to your form in the IDE. Share this post Link to post
dummzeuch 1526 Posted Saturday at 11:51 AM (edited) Instead of setting a unique name, you can set it to an empty string. And what you show in the screen shot is not the memo's name but the memo's Lines property contents. You can set that easily to whatever you want either. Memo.Lines.Text := 'bla blub'; But that's not what was meant when you were told use frames: Just design a frame the way you want it, and create multiple instances of that particular frame class. Edited Saturday at 11:54 AM by dummzeuch Share this post Link to post
JohnLM 23 Posted Saturday at 09:48 PM (edited) When you add a memo or memos to a form, the default behavior is that Delphi will give the .Name and .Text properties a detault value and assign them the same string to represent that component. Thus, memo1.name=memo1 for instance. It prefills this info for our reference at design-time and we can change it or remove it. I myself usually remove it, the .Text portion and I will usually rename .Name to something much shorter, like .Name=m2 for instance. procedure TForm1.btnAddClick(Sender: TObject); var TabSheet: TTabSheet; memo: unit2.TFrame2; begin inc(idx); TabSheet := TTabSheet.Create(PageControl1); TabSheet.Caption := 'Untitled-'+idx.ToString; TabSheet.PageControl := PageControl1; memo := tframe2.Create(nil); memo.Parent := tabsheet; memo.Name := 'Untitled'+idx.ToString; memo.memo1.Align := alClient; memo.memo1.Lines.Add(memo.name); // <-- this line will show the memo's .Name portion in each dynamically create new tab/memo. memo.memo1.Show; memo.memo1.SetFocus; end; I guess I don't actually need the .Name portion to show. I was just trying to demonstrate to myself that I was creating unique tabs AND memo's successfully as demonstrated above. Edited Saturday at 09:57 PM by JohnLM typo and added updated source code and added an image Share this post Link to post
Remy Lebeau 1449 Posted Saturday at 10:41 PM On a side note - the TFrame should have an Owner assigned, not just a Parent, eg: memo := tframe2.Create(TabSheet); 1 Share this post Link to post
JohnLM 23 Posted yesterday at 12:13 PM (edited) I had to change the memo to frame2. The memo is inside the frame. update code snippet #4 procedure TForm1.btnAddClick(Sender: TObject); var TabSheet: TTabSheet; frame2: unit2.TFrame2; begin inc(idx); TabSheet := TTabSheet.Create(PageControl1); TabSheet.Caption := 'Untitled-'+idx.ToString; TabSheet.PageControl := PageControl1; frame2 := tframe2.Create(nil); frame2.Parent := tabsheet; frame2.Name := 'Untitled'+idx.ToString; frame2.memo1.Align := alClient; frame2.memo1.Lines.Add(frame2.name); // <<-- this line will show the memos .Name portion in each dynamically create new tab/memo. frame2.memo1.Show; frame2.memo1.SetFocus; end; Next steps is to get the text from whichever memo I am typing in the tabsheet. That should be easy, I think I just need to grab the frame.memo1.lines or frame.memo1.text should return the text from any memo I am currently typing in. I will look into later today. I have to get some sleep now. until then. . . Edited 8 hours ago by JohnLM Share this post Link to post
JohnLM 23 Posted 7 hours ago Progress update. . . -- on that last next steps I just mentioned, to pull the text from the active tabsheet for the memo I am focused in. . . I have successfully figured out how to pull the text from the dynamically created memo's. It was quite difficult to solve, but I did it. And I did not copy someone else's code snippet. And the code snippet to accomplish it: procedure TForm1.PageControl1Change(Sender: TObject); var frame : TFrame2; edit : TEdit; pgCount : integer; tabIdx : integer; begin tabIdx := PageControl1.ActivePageIndex; pgCount := pagecontrol1.PageCount; frame := (pagecontrol1.Pages[tabIdx].Components[0] as tframe2); edit := (pagecontrol1.Pages[tabIdx].Components[1] as TEdit); StrLines.Assign(frame.memo.Lines); listbox1.Items.Assign(frame.memo.Lines); end; Output results are: text from each memo (left pane) is copied into the listbox (right pane) for proof of concept. All this is part of a project that I am working on, to create a tiny hobby IDE for Python for myself. It appears that this topic has been solved. Share this post Link to post
Remy Lebeau 1449 Posted 59 minutes ago That code can be simplified: procedure TForm1.PageControl1Change(Sender: TObject); var sheet : TTabSheet; frame : TFrame2; begin sheet := PageControl1.ActivePage; frame := sheet.Components[0] as TFrame2; StrLines.Assign(frame.Memo.Lines); ListBox1.Items.Assign(frame.Memo.Lines); end; Share this post Link to post