How to show a form? lazarus / 8-Other ---------------------------------------------------------------------- rturney · 2007-01-26 00:34 I'm making good progress with Lazarus as a former Turbo Pascal enthusiast and current VB developer, but I haven't had to use multiple forms until now and can't find out how to do it  :shock:   I have tried for two days to get to the Lazarus Wiki, but no luck!  (can't connect - times out) So I am trying to get some help from the forum.  To make things simple I started a new project that has Form1 and only a Button (Button1) on it.  I would like to click this button and show a new Form (Form2).  When I added the second form to the project it created a second unit.  So now I have Unit1 with Form1 and Unit2 containing Form2.  The code I have proposed make Form2 appear with a button click is: Code: [Select]procedure TForm1.Button1Click(Sender: TObject); begin   Form2.ShowModal;   Form2.Free; end; Which fails with "Error: Identifier not found "Form2" I'm sure there needs to be some sort of connection between Unit1 and Unit2 so that Form2 can be recognized.  I'm just having a hard time finding info on this, even though it is very elementary.  The Wiki being down is making it worse. Here is Unit1 Code: Code: [Select]unit Unit1; {$mode objfpc}{$H+} interface uses   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Buttons; type   { TForm1 }   TForm1 = class(TForm)     Button1: TButton;     procedure Button1Click(Sender: TObject);   private     { private declarations }   public     { public declarations }   end; var   Form1: TForm1; implementation { TForm1 } procedure TForm1.Button1Click(Sender: TObject); begin   Form2.ShowModal;   Form2.Free; end; initialization   {$I unit1.lrs} end. And here is Unit2 code: Code: [Select]unit Unit2; {$mode objfpc}{$H+} interface uses   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, StdCtrls; type   { TForm2 }   TForm2 = class(TForm)     Label1: TLabel;   private     { private declarations }   public     { public declarations }   end; var   Form2: TForm2; implementation initialization   {$I unit2.lrs} end. Hope someone would offer a clue or direct me to a website that could get me going. Thanks, -Bob ---------------------------------------------------------------------- felipemdc · 2007-01-26 02:27 > I'm sure there needs to be some sort of connection between Unit1 and Unit2 so that Form2 can be recognized. The connection between units is the "uses" clause. Each unit can have potentially 4 sections: interface, implementation, initialization and finalization. And each of these can have a uses clause. If you add a unit to the interface uses clause, you can use things from it on all sections. If you add to the implementation, you can use it on the implementation only (maybe the other 2 too, but I don´t remember). You cannot have 2 units refer to each other on the interface uses clause, because that could generate cyclic references. (i.e. object A inherits from object B, but object B inherits from object A). Here is how you could do it: unit Unit1; {$mode objfpc}{$H+} interface uses   Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, Buttons,   unit2; .......... Or, if you are sure you don´t need to use unit 2 on the interface section, it´s better to do this: ....... implementation uses unit2; ....... A good place to learn about Object Pascal is here: www.delphibasics.co.uk ---------------------------------------------------------------------- Zorba · 2007-01-26 02:39 As sekel already mentioned you need Unit2 in uses clause on Unit1. Also this will thow an exception after the second time that you press the button: Code: [Select] procedure TForm1.Button1Click(Sender: TObject); begin   Form2.ShowModal;   Form2.Free; end; better to free form2 from form2 and leave this on unit1: Code: [Select] procedure TForm1.Button1Click(Sender: TObject); begin   Form2.ShowModal; end; ---------------------------------------------------------------------- rturney · 2007-01-26 04:00 sekel and Zorba I am very grateful that you would take your valuable time to assist with such fundamental questions as mine.  This has really helped me.  I plan to spend a lot of time using and enjoying Lazarus and hope to contribute as much as I have been taking. -Bob ---------------------------------------------------------------------- matthijs · 2007-01-26 19:34 As you tried to free form2 after the showmodal it might be a good idea to do it like this: Code: [Select] procedure TForm1.Button1Click(Sender: TObject); begin   Form2 := TForm2.Create(nil);   try     Form2.ShowModal;   finally     Form2.Free;   end; end; This way you will not get an access violation if you hit the button for a second time. ---------------------------------------------------------------------- felipemdc · 2007-01-26 22:31 To do like matthijs said, it´s nice to remove Form 2 from the auto- create list of forms. Don´t remember which menu item has this list but it should be easy to find. ---------------------------------------------------------------------- rturney · 2007-01-27 05:57 What is puzzling to me is what causes the access violation the second time Form2 is invoked?  Is it because, as matthijs has implied with the code sample, that the Form2 object, once "Free'd" must be created again before it can be shown again? Also what is the difference between Form2 := TForm2.Create(nil)   and Form2 := TForm2.Create(self)  ? -Thanks ---------------------------------------------------------------------- rturney · 2007-01-27 06:58 Also, I assume that in the code below, that without the Form2.Free statement, if Form2 is shown and then "killed" by clicking the "X" (in the upper left corner of the form) that Form2 is merely hidden and not removed from the memory heap.  But wastes memory if it is not being used again. Code: [Select]procedure TForm1.Button1Click(Sender: TObject); begin      Form2.ShowModal; end; And in this code, if Form2 is killed, then the Form2.Free statement removes it from memory? And if the Button1Click procedure is executed again, Form2 has been erased from memory and raises the access violation? Code: [Select]procedure TForm1.Button1Click(Sender: TObject); begin      Form2.ShowModal;      Form2.Free; end; So finally, Form2, if "Free'd" from memory, must be recreated each time it is invoked? Code: [Select]procedure TForm1.Button1Click(Sender: TObject); begin   Form2 := TForm2.Create(nil);   try      Form2.ShowModal;   finally      Form2.Free;   end; end; -Thanks ---------------------------------------------------------------------- eric · 2007-01-27 07:48 QuoteAlso what is the difference between Form2 := TForm2.Create(nil) and Form2 := TForm2.Create(self) ? The item in brackets is the owner of the object being created. Objects don't have to have owners, so you can put 'nil' there. If you use the first method, then you have to explicitly destroy the object after use with 'Form2.Free;' but if you use the second method, then Form2 will be automatically destroyed when 'Self' is destroyed. Eric ---------------------------------------------------------------------- felipemdc · 2007-01-27 10:42 Quote from: "rturney"What is puzzling to me is what causes the access violation the second time Form2 is invoked?  Is it because, as matthijs has implied with the code sample, that the Form2 object, once "Free'd" must be created again before it can be shown again? Yes, that´s it. After you free a form, you can no longer access it. It no longer exists. If you want to access it again, you need to recreate it. QuoteAlso, I assume that in the code below, that without the Form2.Free statement, if Form2 is shown and then "killed" by clicking the "X" The X doesn´t kill the form. It "closes" it, that´s the usual term for this. Closing the form does not imply it is destroyed, where destroyed=free=deallocate memory Usually after close a form is just hidden, and can be shown again. There is a special option that makes forms being shown modally automatically free themselves once they are closed. ---------------------------------------------------------------------- rturney · 2007-01-28 03:18 Thanks for the clarifications!  Now that I have this knowledge I have explored the example in the wiki about MySQL database tutorial but have run into an error related to this Form discussion that I can't figure out.  I have entered the entire tutorial into a new Lazarus project which builds successfully.  But then displays the following message: QuoteError reading OpenQueryButton.OnClick: Invalid value for property Press OK to ignore...etc. I have tried to uncover the problem myself and have replaced "self" with "nil" but still get the same error.  Here is the subroutine, which is exactly what the tutorial shows, with the exception of the "try" and "finally".  I commented them out too, but get the same error. Code: [Select]procedure TForm1.OpenQueryButtonClick(Sender: TObject); begin   ShowQueryForm := TShowQueryForm.Create(self);   try      ShowQueryForm.Datasource1.DataSet := SQLQuery1;      SQLQuery1.SQL.Text := CommandEdit.Text;      SQLQuery1.Open;      ShowQueryForm.ShowModal;   finally      ShowQueryForm.Free;      SQLQuery1.Close;   end; end; I have examined the object inspector for this control to see if there are some suspicious properties. But don't see anything. Any ideas would be appreciated. ---------------------------------------------------------------------- rturney · 2007-01-30 23:35 No replies needed, I found the problem that was causing the error message. :-) ---------------------------------------------------------------------- felipemdc · 2007-01-31 00:35 Quote from: "rturney"No replies needed, I found the problem that was causing the error message. :-) If you tell us what was wrong, people searching the forum in the future can see the solution, if they face the same problem. thanks, ---------------------------------------------------------------------- rturney · 2007-01-31 23:48 Before posting that I had discovered what was causing the Error, I abandoned  the first work I did on the tutorial and started over.  I believed that I had tried too many things to get the second form to be recognized by the first unit and had corrupted the code.  With the knowledge I got from the replies to this thread I recreated the project with a new project name and it ran without the "Error reading OpenQueryButton.OnClick: Invalid value for property" error!  I used all the example subroutines as before so was stumped as to what went wrong in the first attempt.  I compared them side by side and saw no coding differences.  I did this many times to make sure I wasn't overlooking something.  Then I saw that the "first attempt" second unit files were not in the project directory and assumed that that was the problem.  I then posted that I had found the problem.  After that I copied the second unit's files into the correct directory and tried to recompile it.  That was not the problem because the same error returned again.  Since then I have been carefully comparing the two projects and don't have a clue as to why the first one still raises that error! ---------------------------------------------------------------------- felipemdc · 2007-02-01 00:27 Maybe it´s a Mandelbug =) http://en.wikipedia.org/wiki/Unusual_software_bug#Heisenbugs ---------------------------------------------------------------------- rturney · 2007-02-01 05:01 LOL!  Thanks for the link.  Makes me reminisce about a bug I had several years ago in VB6 project that to this day I still do not know what caused it!  It would appear randomly and harmlessly display a message box with an OK button.  It had Mandelbug-ish characteristics.  It never could be trapped, but after clicking OK would allow execution to continue unaffected.  Strangely, it only seemed to occur in the VB IDE and no end users ever reported it to me.  It still drove me crazy!