views:

910

answers:

5

To avoid singletons and global variables I'd like to be able to pass parameters to a TFrame component. However since a TFrame normally is included on form at design time it is only possible to use the default constructor.

The parent form can of course set some properties in the OnCreate callback after the TFrame has been created. However this does not ensure that a property is not forgotten, and the dependencies are not as clear as using a constructor.

A nice way would be if it was possible to register a factory for creating components while the dfm file is being read. Then the required parameters could be passed to the TFrame constructor when created by the factory. Is there a way of accomplishing this?

Or does anyone have a better solution on how to pass parameters to a TFrame?

A: 

could you create/registercomponent your own tFrame component and place that on the form - it's create could have anything passed to it.

Custom constructors aren't called during streaming. Only the Create(TComponent) constructor is called because that's the one inherited from TComponent.
Rob Kennedy
A: 

If a factory could provide the parameters that you need, why don't you just override the default constructor for your frame, and ask the factory-class for parameters?

I usually make my own constructor. I don't like to create frames at designtime anyway.

Vegar
"and as a factory-class"? That sentence doesn't parse.
Rob Kennedy
Woops. I guess I forgot to compile and run unittests before I checked in...
Vegar
+3  A: 

All components, including descendants of TFrame, need to be able to be constructed using the constructor inherited from TComponent. Otherwise, they can't be used properly at design time. If the restriction of design-time use is acceptable to you, then you could override that constructor and raise an exception. That would prevent the component from being placed on a form at design time. Simply provide some other constructor that requires other parameters.

Because of the design-time requirement, all components need to be able to exist with some or all of their properties still at their default values. That doesn't mean the components have to do useful things while they're in that state, but they do need to be able to stay in that state indefinitely. It should be OK, for example, to place a component on a form, save the form, and close Delphi, with the intention of resuming the form-designing at a later time. The component should allow itself to be saved and restored, even if all its properties haven't been set up for final use yet.

My preferred option is to enforce the component's rules only at run time. Check that all the properties are set to sensible values before you allow them to be used. You can use assertions to enforce the proper use of your components. Consumers of your classes will learn very quickly if they haven't finished setting up your components on their forms.

Rob Kennedy
I guess this is the "Delphi way" of doing it. I was trying to separate object creation from the logic of the application by using factories (see http://misko.hevery.com/2008/08/21/where-have-all-the-singletons-gone/)
ajob
A: 

I would normally add a public, non-virtual "Initialise" or (Initialize to Americans) procedure which requires all parameters to be provided. This will then set the properties.

Make the properties protected or private if possible, so the only way they can be set is from calling Initialise(AFoo, ABar : integer).

Then in TFormXXX.FormCreate or TformXXX.Create, have:

inherited;
Initialise(foo, bar);
Gerry
A: 

a) a frame can be created dynamically when required and destroyed when not needed

b) give the frame a public property with either the parameter data type or a data structure and pass the values to the form through the property.

Example:
TAddress - a class to hold the usual elements of an address.
TAddressFra - a frame with the visual controls to display the address

  • populate an instance of TAddress with values
  • create an instance of TAddressFra
  • assign the TAddressFra.address property with the TAddress instance
  • use the procedure setAddress(o_address : TAddress) to assign the values of the TAddress attributes to the corresponding visual components on the TAddressFra
John Wellum