Alan Colburn wrote:
> I cannot tell you how frustrated I am that I apparently *still* don't
> fully understand communication between classes/forms!

First, I'll point out that forms *are* classes. Every time you define a 
new form, you're defining a new class. You can see that in the source 
code. So anything you can do with a class, you can do with a form.

> I won't share
> all my code with you, but let me tell you what I was trying to do &
> hopefully one of you can explain to me what's going on so I can
> understand, once and for all. The basic problem is to create a class
> which will take care of saving values at shutdown and loading them at
> startup, i.e., a config file. [I understand iniFiles and regIniFiles;
> that is not the issue.]
> 
> For the sake of argument, suppose I wanted to store values related to
> the main form, a component on the form, and a class property. I think
> that takes care of most possibilities :-)

Well, the main form is a class, and a component is a class. So if you 
know how to save stuff for entire classes and for single properties, 
you're all set.

> I am apparently confused and clueless regarding issues like what
> parameters I need to have in the IniClass's method signatures,
> whether they are sent by reference or by value (even though I thought
> I understood that, thanks to you folks),

Everything is passed by value, unless you specifically tell it not to by 
using the "var" or "out" keywords.

Some confusion with that may come from the fact that class instances are 
always accessed by reference. When you have a variable in your program 
like this:

var
   Form1: TForm1;

That's not defining an instance of the TForm1 class. Instead, it's just 
a reference variable. It might refer to _any_ instance of TForm1. There 
may be many instances of that class, but the Form1 variable can only 
refer to one of them. It might also refer to none of them, in which case 
its value is nil.

So when you pass Form1 to a procedure by value, you're passing a copy of 
the reference. You're not passing a copy of the entire form instance, 
though, since the Form1 variable never held such a thing. Form1 only 
holds a reference, so the reference gets passed by value.

It's possible to pass a reference by reference. That's what you get with 
a signature like this:

procedure Foo(var Bar: TFont);

It's not often that you see such a signature. It would mean that Foo 
might change the value of Bar. That is, it would make Bar _refer_ to a 
totally different TFont instance. More likely, Foo only needs to change 
the properties of the TFont instance it's given. That doesn't require 
changing the value of Bar. Bar can continue refering to the same TFont 
object it started with. Since the variable doesn't reference anything 
different, its value stays the same and therefore doesn't need the "var" 
keyword.

> and even where it's best to
> instantiate IniClass instances (I don't fully understand why I can
> save and retrieve Form1 values when I instantiate the IniClass in the
> initialization section of Form1...How can you set Form1's Top,
> Height, etc. before Form1 has been created?).

You can't. That might be a source of some of your problems.

> At first I tried initiating an instance of the IniClass in the Form1
> OnCreate event,

Wait just a moment. It's not the Form1 OnCreate event. Form1 is a 
variable. Like I said above, it may refer to one of many instances of 
the TForm1 class. OnCreate is a method of TForm1. It doesn't belong to a 
variable. This is part of a larger issue, which I'll get to.

> passing a reference to Form1 itself to the
> IniClass--thinking that would allow me to pass not only properties
> from Form1 but also therefore Form1's components, or at least Form1
> public properties that I created to hold class level variables.

OnCreate belongs to the entire class, not just one variable of that 
class's type. _Any_ instance of TForm1 might have the OnCreate method 
called on it. You don't really want _all_ of those invocations to always 
load or save data for the single instance referenced by the global Form1 
variable. Rather, you want each invocation to load or save data 
associated with the TForm1 instance upon which the OnCreate method was 
just called. In other words, you want each form to have data loaded or 
saved for itself. That's what the Self variable is for.

In fact, it would be best if you simply deleted the Form1 variable from 
your program altogether. There is (almost) absolutely no need for it. 
All it does is encourage poor programming practice. (Don't take this 
personally. I blame Borland, not you!)

There is just one place where you need a standalone variable for Form1. 
That's in your DPR file, right above the one (!) call to 
Application.CreateForm. CreateForm needs a variable, but you don't need 
that variable anywhere else.

var
   Form1: TForm1;
begin
   Application.Initialize;
   Application.CreateForm(TForm1, Form1);
   Application.Run;
end.

> Form1's properties are properly set, but Form1 component properties
> and variables aren't passed:
> 
> type
> TIniClass=class(TObject)
> private
> public
>   procedure readConfig (var Form1:TForm);
>   procedure write Config (var Form1:TForm);

Based on what I wrote above, you should now recognize that you don't 
need the "var" part on either of those methods. Neither one of those 
methods will cause the actual parameter to refer to a different TForm 
instance.

But there's another problem with those declarations. Those methods are 
declared to receive references to a TForm. That's *any* TForm. That's 
the TForm class declared in the Forms unit.

So you ask why you can't access any fields or properties of your form 
class? Well, that's because TForm doesn't _have_ any such fields or 
properties. TForm only has what was given to it in Forms.pas. All your 
fields and properties were added in your TForm1 class declaration.

If those configuration methods are always going to act on TForm1 
instances, then change their declarations to use TForm1 instead of the 
generic TForm.

> I sort of understand why component properties would be inaccessible,
> but I don't understand why the class properties wouldn't be
> accessible.

Just a note on terminology. When you place a component on your form in 
the Form Designer, the IDE declares a new *field* in the corresponding 
class declaration. Those components aren't properties. Properties are 
things declared using the "property" keyword. And just to add to the 
confusion, Delphis 2005 and 2006 support the notion of a "class 
property," which is different from a regular property. They're like 
class methods, which are methods that can be accessed without referring 
to any instance of the class. Likewise with class properties. You don't 
need an instance of the class, and accessing the property through an 
instance reference will always access the same value shared between all 
instances. Probably not what you were intending to talk about.

-- 
Rob
_______________________________________________
Delphi mailing list -> [email protected]
http://www.elists.org/mailman/listinfo/delphi

Reply via email to