Recent

Author Topic: how to modify or add component after Application.Run method?  (Read 7940 times)

bee

  • Sr. Member
  • ****
  • Posts: 393
how to modify or add component after Application.Run method?
« on: January 24, 2016, 10:04:01 am »
Hi all,

Common Lazarus project source code contains this snippet:

Code: Pascal  [Select][+][-]
  1. begin
  2.   Application.Initialize;
  3.   Application.CreateForm(TForm, Form1);
  4.   Application.Run;
  5. 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][+][-]
  1. begin
  2.   Application.Initialize;
  3.   Application.CreateForm(TForm, Form1);
  4.   Application.Run;
  5.   // how to make below code be executed?
  6.   Form1.Caption := 'My caption';
  7.   Form1.Edit1.Text := 'My text input';
  8.   MyLabel := TMyLabel.Create(Form1);
  9.   MyLabel.Parent := Form1;
  10.   MyLabel.Caption := 'My runtime label';
  11.   // or one could add any arbitraty code here
  12. end.

Thank you. :)

Regards,

–Mr Bee
-Bee-

A long time pascal lover.

FTurtle

  • Sr. Member
  • ****
  • Posts: 292
Re: how to modify or add component after Application.Run method?
« Reply #1 on: January 24, 2016, 11:05:42 am »
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][+][-]
  1.   Application.CreateForm(TForm1, Form1);
  2.   // here
  3.   Application.Run;
  4.  

2. In Form1.pas:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. begin
  3.   // here
  4. end;
  5.  

The second is better.

P.S. Just in case, I remind that in the second case you should not use variable Form1.

« Last Edit: January 24, 2016, 11:24:07 am by FTurtle »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: how to modify or add component after Application.Run method?
« Reply #2 on: January 24, 2016, 11:06:38 am »
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.
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

Leledumbo

  • Hero Member
  • *****
  • Posts: 8835
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: how to modify or add component after Application.Run method?
« Reply #3 on: January 24, 2016, 05:53:54 pm »
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

  • Sr. Member
  • ****
  • Posts: 292
Re: how to modify or add component after Application.Run method?
« Reply #4 on: January 24, 2016, 06:52:33 pm »
Code: Pascal  [Select][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Interfaces, // this includes the LCL widgetset
  10.   Forms, Unit1
  11.   { you can add units after this };
  12.  
  13. {$R *.res}
  14.  
  15. begin
  16.   RunApp;
  17.   //RequireDerivedFormResource:=True;
  18.   //Application.Initialize;
  19.   //Application.CreateForm(TForm1, Form1);
  20.   //Application.Run;
  21. end.
  22.  

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;
  9.  
  10. procedure RunApp;
  11.  
  12. type
  13.   TForm1 = class(TForm)
  14.   private
  15.     { private declarations }
  16.   public
  17.     { public declarations }
  18.   end;
  19.  
  20. var
  21.   Form1: TForm1;
  22.  
  23. implementation
  24.  
  25. {$R *.lfm}
  26.  
  27. procedure RunApp;
  28. begin
  29.   RequireDerivedFormResource:=True;
  30.   Application.Initialize;
  31.   Application.CreateForm(TForm1, Form1);
  32.   Application.Run;
  33. end;
  34.  
  35. end.
  36.  

Leledumbo

  • Hero Member
  • *****
  • Posts: 8835
  • Programming + Glam Metal + Tae Kwon Do = Me
Re: how to modify or add component after Application.Run method?
« Reply #5 on: January 24, 2016, 07:38:01 pm »
@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

  • Sr. Member
  • ****
  • Posts: 292
Re: how to modify or add component after Application.Run method?
« Reply #6 on: January 24, 2016, 07:54:42 pm »
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.

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

  • Hero Member
  • *****
  • Posts: 2330
Re: how to modify or add component after Application.Run method?
« Reply #7 on: January 24, 2016, 08:00:26 pm »
Quote
FTurtle 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

  • Hero Member
  • *****
  • Posts: 2330
Re: how to modify or add component after Application.Run method?
« Reply #8 on: January 24, 2016, 09:22:44 pm »
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][+][-]
  1. program project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Interfaces, // this includes the LCL widgetset
  10.   Forms, Unit1, Unit2
  11.   { you can add units after this };
  12.  
  13. {$R *.res}
  14.  
  15. begin
  16.   RequireDerivedFormResource := True;
  17.   Application.Initialize;
  18.   Application.CreateForm(TDataModule1, DataModule1);
  19.   Application.Run;
  20. end.
  21.  

mainform
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;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     procedure FormCreate(Sender: TObject);
  16.   private
  17.     { private declarations }
  18.   public
  19.     { public declarations }
  20.   end;
  21.  
  22. var
  23.   Form1: TForm1;
  24.  
  25. implementation
  26.  
  27. {$R *.lfm}
  28.  
  29. Uses
  30.   StdCtrls;
  31.  
  32. procedure AddLabel(const ACaption: String; const l,t,w,h: LongInt);
  33. var
  34.   ALabel: TLabel;
  35. begin
  36.   ALabel := TLabel.Create(Form1);
  37.   with ALabel do begin
  38.     Parent := Form1;
  39.     SetBounds(l,t,w,h);
  40.     Caption := ACaption;
  41.   end;
  42. end;
  43.  
  44. { TForm1 }
  45.  
  46. procedure TForm1.FormCreate(Sender: TObject);
  47. begin
  48.   Caption := 'caption set in on create event of form';
  49.   AddLabel('Test Aja',10,10,50,40);
  50. end;
  51. end.
  52.  
And yes, you can take away the form resource, just as in Leledumbo's example.

datamodule:
Code: Pascal  [Select][+][-]
  1. unit Unit2;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil;
  9.  
  10. type
  11.  
  12.   { TDataModule1 }
  13.  
  14.   TDataModule1 = class(TDataModule)
  15.     procedure DataModuleCreate(Sender: TObject);
  16.   private
  17.     { private declarations }
  18.   public
  19.     { public declarations }
  20.   end;
  21.  
  22. var
  23.   DataModule1: TDataModule1;
  24.  
  25. implementation
  26.  
  27. {$R *.lfm}
  28.  
  29. Uses
  30.   Forms, Unit1;
  31.  
  32. { TDataModule1 }
  33.  
  34. procedure TDataModule1.DataModuleCreate(Sender: TObject);
  35. begin
  36.   Application.CreateForm(TForm1, Form1);
  37.   Form1.Caption := 'Test';
  38. end;
  39.  
  40. end.
  41.  

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

  • Hero Member
  • *****
  • Posts: 5368
Re: how to modify or add component after Application.Run method?
« Reply #9 on: January 24, 2016, 10:59:02 pm »
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.
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

molly

  • Hero Member
  • *****
  • Posts: 2330
Re: how to modify or add component after Application.Run method?
« Reply #10 on: January 24, 2016, 11:47:42 pm »
I 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 ? :P

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

  • Sr. Member
  • ****
  • Posts: 393
Re: how to modify or add component after Application.Run method?
« Reply #11 on: January 25, 2016, 04:02:10 am »
Hello all… OP here… :D

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][+][-]
  1. program hello;
  2.  
  3. uses crt;
  4.  
  5. var s: string;
  6.  
  7. begin
  8.   clrscr;
  9.   write('What is your name? ');
  10.   readln(s);
  11.   if s <> '' then
  12.     writeln('Hi… '+s+', nice to meet you!');
  13.   readln;
  14. end.
  15.  

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-

A long time pascal lover.

bee

  • Sr. Member
  • ****
  • Posts: 393
Re: how to modify or add component after Application.Run method?
« Reply #12 on: January 25, 2016, 04:19:49 am »
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. :D
-Bee-

A long time pascal lover.

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: how to modify or add component after Application.Run method?
« Reply #13 on: January 25, 2016, 04:54:12 am »
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.

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.
« Last Edit: January 25, 2016, 05:05:25 am by taazz »
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

bee

  • Sr. Member
  • ****
  • Posts: 393
Re: how to modify or add component after Application.Run method?
« Reply #14 on: January 25, 2016, 06:50:49 am »
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.

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. :)

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.
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#.

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.
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.

What 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? :)
« Last Edit: January 25, 2016, 06:58:22 am by bee »
-Bee-

A long time pascal lover.

 

TinyPortal © 2005-2018