[EMAIL PROTECTED] wrote: > 1. I have a piece of code that is killing me: > > I want to create a MDI application. > I have a main form that automatically creates a new child form called > 'Project Manager'. It can't be close, only minimized. It is > automatically destroyed by the application when it terminates. > I use this 'Project manager' to create other (one or more) child forms > called Grids. I should be able to close those forms (caFree) at any time > or I can leave them open and close the application to close them for me > when it finish. The question is: why I can't pass *nil *as parameter > when I create these forms? > > > procedure TFormManager.Start; > begin > with TFormGrid.Create(*nil*) DO <<< if I > pass _Application_ or _Self_, it works! > begin > ...some code here; > end; > end; > > procedure TFormGrid.FormClose(Sender: TObject; var Action: TCloseAction); > begin > Action:= caFree; > end; > > I think until here everything is right. Right?
Well, except for that use of a "with" statement, in which the compiler could be resolving names to values different from what you expected, yes, what you've shown looks fine. > When I close the whole application and one or more of these Grid forms > are open, it crashes in this procedure: > > > procedure TMainForm.FormResize(Sender: TObject); { <- this is > supposed to keep the child forms at the same width with the main form > when the user resize the interface } Maximized windows will do that automatically. If you really only want to change the width, and not the height, you can also try using the Anchors property. > VAR i: Integer; > begin > for I:= MDIChildCount-1 DownTo 0 DO > begin > if (MDIChildren[i] is TFrmGrid) then > if (MDIChildren[i] as TFrmGrid).HandleAllocated You can write that more directly as this: if (MDIChildren[i] is TFrmGrid) and TFrmGrid(MDIChildren[i]).HandleAllocated then Since everything is guarded by the "is" test, you don't need to use the "as" type-casting everywhere. All you're doing is re-checking a type cast that you've already checked. However, you really don't need to do any type-casting at all. All the properties you're accessing belong to the TForm class, which is the type that MDIChildren will return anyway. You only need to type-cast if you need to access a property that's introduced in TFrmGrid. Furthermore, when you have two nested conditionals, you can combine them with "and" into one conditional statement. The second expression is not evaluated if the first is False. > then > begin > if ((MDIChildren[i] as TFrmGrid).WindowState= wsNormal) > <<<< *CRASH HERE*. Exception class C0000005 with message 'access > violation at 0x0055bc6b: read of address 0x00000000'. Turn on the "debug DCUs" compiler option. When the debugger tells you about the exception, does it still crash there, or does it occur somewhere in the VCL source code? It should be the latter, which should provide a more specific source of the problem. Somewhere, your program is dereferencing a nil pointer. > then > begin > (MDIChildren[i] as TFrmGrid).Left:= 0; > (MDIChildren[i] as TFrmGrid).Width:= MainForm.ClientWidth-4; What's the magic number 4? Why not 5 or 36? Don't reference MainForm here. It's a global variable, which refers to one particular instance of TMainForm. That instance isn't _necessarily_ the same as the instance whose FormResize method is running at this point. You're accessing the current form's MDIChildren property, but possibly some other form's ClientWidth property. Do this instead: MDIChilren[i].Width := ClientWidth - 4; Finally, accessing the MDIChildren property so often is a little wasteful. TForm implements its MDIChildren property by looping through the Screen.Forms array and counting all the forms that have the FormStyle property set to fsMDIChild. When it reaches "i", it returns. You're forcing the program to run that loop five times for each MDI child which you could do it in one by using a local variable: var Child: TForm; for i := 0 to Pred(MDIChildCount) do begin Child := MDIChildren[i]; if Child is TFrmGrid and Child.HandleAllocated then begin // ... end; end; > end; > end; > end; > end; > > > I suppose is something with those 'dangling' pointers, so my next > question is: > > > 2. Why Delphi does only a 'Free' on a object/form when it automatically > destroy it instead a FreeAndNil? What, exactly, should get set to nil? How do you know? How should Delphi know? Have you looked at how FreeAndNil actually works? http://www.cs.wisc.edu/~rkennedy/freeandnil > The application works very well with Self or Application instead of Nil > but the documentation says that Application is not recommended because > it is slow and Self should be used OLNY when the Create belongs to the > main form (and in my case I don't create those Grids in the main form). > So the only answer is NIL. Hardly. You can let the owner be anything you want. Nil, Self, and Application are only the most common values. Conceptually, which form owns those grids? -- Rob __________________________________________________ Delphi-Talk mailing list -> Delphi-Talk@elists.org http://www.elists.org/mailman/listinfo/delphi-talk