how to modify or add component after Application.Run method? lazarus / 31-LCL ---------------------------------------------------------------------- bee · 2016-01-24 09:04 Hi all, Common Lazarus project source code contains this snippet: 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 begin  Application.Initialize;  Application.CreateForm(TForm, Form1);  Application.Run;end. Adding code to modify or add components of/into Form1 after the Application.Run method will be ignored because it's out of the application's main thread. So, is there a correct and safe way to do it? 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 begin  Application.Initialize;  Application.CreateForm(TForm, Form1);  Application.Run;  // how to make below code be executed?  Form1.Caption := 'My caption';  Form1.Edit1.Text := 'My text input';  MyLabel := TMyLabel.Create(Form1);  MyLabel.Parent := Form1;  MyLabel.Caption := 'My runtime label';  // or one could add any arbitraty code hereend. Thank you. Regards, –Mr Bee ---------------------------------------------------------------------- FTurtle · 2016-01-24 10:05 Most of the GUI-application work takes place inside Application.Run When you run Application.Run, the main form becomes visible. When you close main form, you exit from Application.Run and after from application at all. So, you can insert your code: 1. In .lpr somewhere between lines: 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   Application.CreateForm(TForm1, Form1);  // here  Application.Run;  2. In Form1.pas: 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 procedure TForm1.FormCreate(Sender: TObject);begin  // hereend;  The second is better. P.S. Just in case, I remind that in the second case you should not use variable Form1. ---------------------------------------------------------------------- taazz · 2016-01-24 10:06 Forget the the project source code, use the form's OnCreate event. There is never a need to change the project's source code well almost there are one or two reasons that changing the project's source code might be the only solution the one you showed here is not one of them. ---------------------------------------------------------------------- Leledumbo · 2016-01-24 16:53 The OP is a friend of mine. He's trying to make 3 units with the same interface capable of producing console, gui and web app only by the change of corresponding unit in uses clause. For the gui part, I speculate to him (after stating the limitation that main program can't be interactive and mainly consist of form elements building) that it might be possible to call Application.Run in the finalization section of the unit, but apparently this fails. The form doesn't show, it's just the program won't terminate. The current state is as the attachment (adjust opt.cfg and compile from command line with fpc @opt.cfg pformtest.pas), which shows above behavior. If Application.Run is moved to before end. in pformtest.pas, then it will work as expected. Any idea to make it possible without explicitly including Application.Run in the main program? ---------------------------------------------------------------------- FTurtle · 2016-01-24 17:52 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 program project1; {$mode objfpc}{$H+} uses  {$IFDEF UNIX}{$IFDEF UseCThreads}  cthreads,  {$ENDIF}{$ENDIF}  Interfaces, // this includes the LCL widgetset  Forms, Unit1  { you can add units after this }; {$R *.res} begin  RunApp;  //RequireDerivedFormResource:=True;  //Application.Initialize;  //Application.CreateForm(TForm1, Form1);  //Application.Run;end.  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 Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs; procedure RunApp; type  TForm1 = class(TForm)  private    { private declarations }  public    { public declarations }  end; var  Form1: TForm1; implementation {$R *.lfm} procedure RunApp;begin  RequireDerivedFormResource:=True;  Application.Initialize;  Application.CreateForm(TForm1, Form1);  Application.Run;end; end. ---------------------------------------------------------------------- Leledumbo · 2016-01-24 18:38 @FTurtle: That's not exactly what the OP wants. Main program block must stay clear (it may only contain user defined code), hence the idea of calling Application.Run in finalization section. ---------------------------------------------------------------------- FTurtle · 2016-01-24 18:54 Quote from: Leledumbo on January 24, 2016, 07:38:01 pmThat's not exactly what the OP wants. Main program block must stay clear (it may only contain user defined code), hence the idea of calling Application.Run in finalization section. All of this looks little strange. May be better try to find other solution? For example, I think it is a good idea at least to see this: http://wiki.freepascal.org/Project_Groups I have not watched this yet, so I can't say anything about applicability it in this case. ---------------------------------------------------------------------- molly · 2016-01-24 19:00 QuoteFTurtle wrote All of this looks little strange. Nah, not really strange, just the provided solutions so far. In case i understood correctly: What i usually do is create a module and let the project code do as it does now (no forms created, only the module). Then in the module i decide what needs to be done, e.g. do i need to create  gui or create the non gui version. Forms can be added as normal to the aplpications in case of gui, in case non-gui other modules can be added. Depending on the events that take place things can be a bit awkward, but in that case i point to topic starter to reveal what problems he encounters using such solution. ---------------------------------------------------------------------- molly · 2016-01-24 20:22 and this shows how it can be done, but tbh i think there is more to it then already discussed. project sourcecode: 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 program project1; {$mode objfpc}{$H+} uses  {$IFDEF UNIX}{$IFDEF UseCThreads}  cthreads,  {$ENDIF}{$ENDIF}  Interfaces, // this includes the LCL widgetset  Forms, Unit1, Unit2  { you can add units after this }; {$R *.res} begin  RequireDerivedFormResource := True;  Application.Initialize;  Application.CreateForm(TDataModule1, DataModule1);  Application.Run;end.  mainform 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 Unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs; type   { TForm1 }   TForm1 = class(TForm)    procedure FormCreate(Sender: TObject);  private    { private declarations }  public    { public declarations }  end; var  Form1: TForm1; implementation {$R *.lfm} Uses  StdCtrls; procedure AddLabel(const ACaption: String; const l,t,w,h: LongInt);var  ALabel: TLabel;begin  ALabel := TLabel.Create(Form1);  with ALabel do begin    Parent := Form1;    SetBounds(l,t,w,h);    Caption := ACaption;  end;end; { TForm1 } procedure TForm1.FormCreate(Sender: TObject);begin  Caption := 'caption set in on create event of form';  AddLabel('Test Aja',10,10,50,40);end;end. And yes, you can take away the form resource, just as in Leledumbo's example. datamodule: 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 Unit2; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, FileUtil; type   { TDataModule1 }   TDataModule1 = class(TDataModule)    procedure DataModuleCreate(Sender: TObject);  private    { private declarations }  public    { public declarations }  end; var  DataModule1: TDataModule1; implementation {$R *.lfm} Uses  Forms, Unit1; { TDataModule1 } procedure TDataModule1.DataModuleCreate(Sender: TObject);begin  Application.CreateForm(TForm1, Form1);  Form1.Caption := 'Test';end; end.  Feel free to place the label creation wherever you want it to be (although i agree with FTurtle and Taaz that they should go in form creation -> and use generic add routines outside of there to be called depending on the situation) Note that removing stuff from form.create that the datamodule takes care of setting the caption. (just as it is possible to let it take care of the label creation). The thing i might perhaps remember wrong in relation to delphi solution is that i seem to remember being able to explicitly set which form the application needs to display (and i seem unable to let lazarus do something similar or i have overlooked). ---------------------------------------------------------------------- taazz · 2016-01-24 21:59 I do not understand the problem. On one hand finalization section of a unit is executed when the application exits and unloads it self from memory which makes it a bit weird of a place to call application.run. On the other hand there is the problem with the difference between console applications, lcl applications, and web applications which makes things a lot more complicated than a unit change. First of all a lazarus project has more information than the units, each package used adds its own search paths and links to existing dlls. Lets assume for a moment that all that will never be a problem how do you combine 3 different programming methodologies under a single main block? on one hand you have the "interactivity" of a console application where the user gets to focus on each required parameter exclusively with the "event" based application where everything is set up at the start the end user can change anything he wants on the screen in which ever order he pleases and finally the web interface where once set you have no control what so ever what the end user will see in which order and even if the processing will be done server side or not you only provide the data not the client interface which can be changed by anyone on the clients end. What is the OP after? Writing a single application flow in the main block and have each type of application emulate that? eg have a lcl application that will emulate a console flow a web application that will do the same with html pages and a classic console application? Everything is possible as long as there are specifics we can work with adding a control to a form is hardly enough information on this problem. ---------------------------------------------------------------------- molly · 2016-01-24 22:47 Quote from: taazz on January 24, 2016, 10:59:02 pmI do not understand the problem. tbh, me neither. Based on the original question "how to modify or add component after Application.Run method?", i showed a solution. hence if the solution presented by me is not applicable, then the question was wrong ? I do not question what TS has in mind, because it is possible to realize something as imagined, just not using the approach of letting things all depend on inclusion of certain units. At least not as presented by Leledumbo. Actually i should say "according to my knowledge". It might very well be that TS has a generic implementation, separating the GUI parts from the usual (common) program flow, and using already present implementations for addressing the different application 'front-ends' depending on whether it is compiled as a console, gui or web application. So, indeed more information would be required if presented solutions are not applicable. ---------------------------------------------------------------------- bee · 2016-01-25 03:02 Hello all… OP here… Thank you for all the answers. I really appreciate it. However, I don't think no answer is able to satisfy my need, yet. Well, sorry if my need sounds weird, but I have a good reason for that. My reason is… I'd like to provide some units to help Pascal newbies leaving the console and procedural programming, step by step. I'd like to introduce them to GUI and web programming. My first approach is to let them using procedural programming to enter GUI and web programming. I don't need fancy features, working readln/writeln methods would be enough, so they would also understand the limitation and problem of using such approach. Consider this common Greeting code: 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 program hello; uses crt; var s: string; begin  clrscr;  write('What is your name? ');  readln(s);  if s <> '' then     writeln('Hi… '+s+', nice to meet you!');  readln;end.  I simply change the "crt" into "webcrt", it suddenly becomes a simple web app. I have succeed making it happen. Take a look at the proof of concept here: http://beeography.koding.io/hello.cgi (source code can also be shown as included feature of the webcrt unit). webCRT unit source code can be read here: http://beeography.koding.io/viewcode.cgi?file=webcrt.pas As I have succeed with the web, I continued with the GUI part… a guiCRT unit. I tried to make the guiCRT unit as the main form iniator and caller, then provide some methods so the user of the unit can put something onto the form (typically just TLabel and TEdit would be enough through writeln/readln helper methods). Unfortunately, my trick fails so far. Hence, this thread. These units are just for introduction to help Pascal newbies learning new and modern programming techniques and paradigms. Slowly bring them out of console and procedural old-school programming. For most of them, absorbing the GUI and web mechanism is quite difficult, let alone learning how to program them. That's why I want to provide them these kind of units. I think it should be possible, it's just the matter of how to do it. So, is there any appropriate and proper way to achieve this? Thank you. ---------------------------------------------------------------------- bee · 2016-01-25 03:19 I think I have a solution. It's not ideal as I thought before, but it's alright, it's still acceptable for my need. Let me try it first. Wish me luck! Anyway… thank you all. ---------------------------------------------------------------------- taazz · 2016-01-25 03:54 Quote from: bee on January 25, 2016, 04:02:10 amThese units are just for introduction to help Pascal newbies learning new and modern programming techniques and paradigms. Slowly bring them out of console and procedural old-school programming. For most of them, absorbing the GUI and web mechanism is quite difficult, let alone learning how to program them. That's why I want to provide them these kind of units. I think it should be possible, it's just the matter of how to do it. So, is there any appropriate and proper way to achieve this? Thank you. Actually you are doing the exact opposite of your goals. By providing a webcrt unit that converts an existing console application to a web application you are helping them to use old and obsolete techniques to work in modern systems thus avoiding to learn the new paradigms and way of thinking. If you want them to learn then teach them to convert the old console applications to FreeVision applications. It will still be a console application but it would be on the new paradigm and would help them understand better what is going on under the hood. you could also help them write some part of the lcl for them self as a learning exercise mainly the most basic, on windows will be the creation of main application loop and message management for the most basic things like keyboard and mouse handling. What you are doing is counter intuitive, by bridging the old with the new you do not help anyone (except your self) to learn. The simplest solution would be to use assembly to find the beginning of the main execution block and call it from the main application loop as a procedure, after that building a writeln replacement should be easy enough although a readln would be a bit more tricky its not impossible to do. At this point I'm going to reference freevision as the most logical step for your goals once more for emphasis and a hope that you will share with us what ever solution you come up with. This problem requires a bit of creativity and smarts, any working solution will be interesting to read. ---------------------------------------------------------------------- bee · 2016-01-25 05:50 Quote from: taazz on January 25, 2016, 04:54:12 amActually you are doing the exact opposite of your goals. By providing a webcrt unit that converts an existing console application to a web application you are helping them to use old and obsolete techniques to work in modern systems thus avoiding to learn the new paradigms and way of thinking. Well, I don't think so. As I said, I want to bring them out of old- school programming techniques into modern programming ones. But I also want to show them that they still can use their existing knowledge with modern technology. This way, they won't feel rejected or useless at the first try. And I hope they will get excited with that and encouraged to learn more. It's only for the first step, I won't use this approach all along the learning process. Once they realize the limitations and problems of using old-school techniques, I'll teach them the new techniques. In the end, they will learn the proper techniques. Quote from: taazz on January 25, 2016, 04:54:12 amIf you want them to learn then teach them to convert the old console applications to FreeVision applications. It will still be a console application but it would be on the new paradigm and would help them understand better what is going on under the hood.As I said, I want to bring them out of console based programming. It's ancient. I want them starting to embrace new technologies, such as GUI, web, and mobile. Giving them FreeVision won't do them any good, at least that's how I see it. I saw many Pascal newbies (that learn using the old way) go away from Pascal with one of the reasons is they think Pascal can't be used with new technologies. So, they learn new language altogether, like PHP, Java, or C#. Quote from: taazz on January 25, 2016, 04:54:12 amYou could also help them write some part of the lcl for them self as a learning exercise mainly the most basic, on windows will be the creation of main application loop and message management for the most basic things like keyboard and mouse handling.As I said, at this step, it's too complicated for them. Most of them couldn't even comprehend how the GUI or web works, let alone how to program them. At this point, they only know how to program in procedural techniques. I think it'd be good and easier for them to start learning new techniques from that point. Quote from: taazz on January 25, 2016, 04:54:12 amWhat you are doing is counter intuitive, by bridging the old with the new you do not help anyone (except your self) to learn.It's alright. It's your view and opinion, I respect it. However, I have my own view and opinion as well which I think better than yours, at least according to me. So, as I have explained my reason and goal, I don't want to argue about it, it's just an FYI thing. Let's focus to the 'how' instead of the 'why', shall we? ---------------------------------------------------------------------- molly · 2016-01-25 16:38 @bee: I don't question your motives as i assume they are sincere, although i do agree with taazz. But, i have a hard time understanding the how part, e.g. how you envision this to be implemented. Object oriented programming requires a different mindset, hence the solutions provided that uses such mindset (and which don't seem to match your idea's). What i seem to understand from your point of view, is that the user still uses procedural routines in order to create an GUI application. This is possible to a certain extend, e.g. implementing events would then be out of the question. But that's rather awkward, to use an object oriented class (such as application), that takes care of talking to the OS and divert incoming user input etc. A class like TApplication is meant to be used in a certain way as shown by the (already available) presented solution(s). In principle it is possible to use only procedural code (except for the application/GUI creation parts) to create simple GUI applications, and the most useable approach would be that of something similar as shown by user FTurtle. But, that can only be done in a sane way by either leaving out the separate project vs form units in which case your project file looks something like: 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 Type  TForm1 = class  ... end; Var  Form1: TForm1; Procedure CreateGUI;begin  Application.CreateForm(TForm1, Form1);  AddLabel(...)  etc...end; begin  Application.Initialize;  CreateGUI()  Application.Run;end. As shown by user FTurtle. Or by using a separate unit that declares the form and implements the CreateGUI() procedure, as also shown by user FTurtle. This is simply how the Application class is intended to work: - Intialize the application - Add forms/modules/etc. - Use either form/module create or other events to make adjustments - make adjustments just before running the application. - Call application's run method, effectively 'handing over control' to the application object, handling the user input - return when application was terminated or all forms closed Additionally you can use Form/Module/Application class events to handle particular events. If that doesn't really suit your needs then i see no other way then to create your own custom application class to be able to do your bidding. In that case something like: QuoteMyCustomApplication.ExecuteProceduralRoutineThatDoesThingsJustbef oreCallingRun(@CreateGUI) comes to mind, although you could achieve the same with the code already shown. Alternatively, it is always possible to create native GUI elements manually, but i guess that would be even more out of scope (as that renders things platform dependent). Or to put it into other words, what is allowed (especially OOP-wise) to achieve your goal ?