-4

I'd like to check from Form1.OnCreate event handler procedure if Form1 constructor Create finished the job with populating all the components on Form1. Then would like to use Form1 to loop through the components and change Text property. I have tried:

WHILE NOT Assigned(Form1) DO 
  Sleep(100); 

... but it didn't work.

Now when I try to use Form1, I get Access Violation error.

  • What are you actually trying to do? I'm sure waiting is not the solution. You have to understand that all your code runs in the same thread (I presume). And you cannot wait on your self. – David Heffernan Feb 20 '14 at 15:07
  • 2
    It seems your are trying to access the class, not an instance? The class is called TForm1, the instance variable is called Form1? You can't use Assigned on the class? – whosrdaddy Feb 20 '14 at 15:11
  • 2
    `while not Assigned(Form1) do Sleep(100)` won't help either. That's a loop that never ends. I urge you to explain the real problem. – David Heffernan Feb 20 '14 at 15:16
  • So the ultimate question is, are you trying to do this from another thread than the main thread? If so, we need to know. If not, then this will never work because as David says, a thread can't wait on its self. – Jerry Dodge Feb 20 '14 at 15:51
  • Do you understand how threads work? The main process thread, only one line of code could possibly be executed at a time. – Jerry Dodge Feb 20 '14 at 17:15
  • I'm trying to change Text property on every TTextControl descendant on the TForm... but I get AV so, I think I do it too fast, when some controls are still not on the form... So @Jerry - I can't belive that I have to use second thread to check if TForm.Create() finished constructing... :/ – Sebastian Xawery Wiśniowiecki Feb 20 '14 at 17:16
  • You don't have to use a second thread. You just have to design your program properly. You were the one that decided you could make your program do nothing, and then hope that it did something. Why oh why won't you ask us about your problem? I recommend you stop asking us how to implement your solutions because usually your solutions are wrong. Ask instead how to tackle your problem. – David Heffernan Feb 20 '14 at 17:19
  • ... in other words... just need information that all the controls on the TForm are ready to use (use - I mean change Text property) – Sebastian Xawery Wiśniowiecki Feb 20 '14 at 17:19
  • program starts -> controls are created -> I need to change language (mnemonics to people's language) -> to do it controls have to be created but when I try, they'are not -> I don't have 300 Euro on TsiLang or other -> I'd like to have my own localization library :) – Sebastian Xawery Wiśniowiecki Feb 20 '14 at 17:26
  • 1
    You might find it is hard to lift a chair while you are sitting on that chair. – Warren P Feb 20 '14 at 17:46
  • It would be extremely helpful if you could show the lines of code where changing the Text property of a TTextControl on the form causes the AV. It would also be very helpful if we could see where in the program you were calling this code - if you have a callstack, that's doubly helpful. – J... Feb 20 '14 at 18:12

2 Answers2

5

This answers address what I think is the real issue as has become apparent from your comments. You should edit the question to include those details that at the moment appear only in comments.

You appear to be trying to make a procedure run whenever a form is created. As I explained above, no good will come of waiting in the main thread. The thing you are waiting for also runs in the main thread. You'll just block forever.

So I won't attempt to explain how to wait, as you asked, because that can never work. That is not the solution to your real problem.

As I understand your problem, based on your recent questions, you are trying to access Application.MainForm in the constructor of said form, and the MainForm property has not yet been initialised. The reason you do that is because you want to walk over all components owned by Application.

Or you want to use the global Form1 variable which is nil during the creation of the form. But you would be well advised to delete that global Form1 variable anyway. Global variables tend to cause trouble. Since you are inside the a method of your form, in a method handler for OnCreate, you can access the form using Self. Always use Self if it is possible to do so.

But that's the wrong way to solve the problem anyway. It denies the existence of forms created after your program has started. You should do what you need to do, on demand, when any form is created.

This is how I would solve your problem:

  1. Declare a new form, derived from TForm, called, for instance, TMyBaseForm.
  2. Add an AfterConstruction procedure, with the override directive.
  3. Implement TMyBaseForm.AfterConstruction to invoke your text changing code. At this point all the design time control exists and have properties streamed.
  4. Make sure that all forms in your application derive from TMyBaseForm.

This design gives you the opportunity to apply consistent behaviour across all GUI elements in your program.

One final comment. You appear to be relatively inexperienced and novice. That's fine, we were all there once. But you will be more successful if you ask questions about your problem rather than about your proposed solution.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
5

The OnCreate event is triggered at the end of the construction of a Form object. A Form's components are created during the construction process before the OnCreate event is triggered. There is no need to "check .. if Form1 constructor Create finished the job" as that is basically guaranteed. Once OnCreate is triggered, you can access the components.

If your Form1 object is created via TApplication.CreateForm() at program startup then the Form1 variable will be assigned a valid but uninitialized object before the constructor is called, and thus will point at a valid object in the OnCreate event.

If your Form1 object is created by calling its constructor in your code, then the Form1 variable will not be assigned until after the constructor exits, and thus will not point at a valid object in the OnCreate event.

Either way, you should not be using the Form1 variable inside of the OnCreate event for the Form1 object to begin with. Use the Self pointer instead, or typecast the event's Sender parameter. Both will point at the same Form1 object that was created.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770