tags:

views:

149

answers:

4

Hi, I've been working on a program in Delphi 2009. It very similar to the program "Mimics" by materialise, where you can create and manipulate 3D meshes. There are 4 panels with different aspects for viewing a 3D object (XY,YZ,XZ, and 3D perspective). Each of the panels is an instance of a custom frame I made for viewing 3D objects. The 4 panels are then loaded onto a form which has buttons and other components.

A problem that I am running into is that the frames must access subroutines of the form on which they reside. E.G. If I change something about the mesh im working on in one of the frames, ALL of the frames should be updated (refreshed) which is a procedure available in the parent form. But to call procedures on the parent form I have to include the parent form's unit file in the implementation uses clause of the 3D frame. That is fine, and this in general works without any trouble. The problem is that I cannot use the parent form to inherit from. If i create an inherited class from the parent form, the unit name and form name change and I must then alter the 3D frame to reference this new changed form.

Thats really the crux of my problem. I dont know how to reference the attributes of a parent form from its child frames without explicitly stating the name of the form. I want to be able to reuse and expand upon the parent form, but I dont see how its possible without also changing the 3D frames which are used by the form.

Any help would be greatly appreciated. Thank you.

+8  A: 

So you have a self-contained component (a frame) that has to be able to invoke code from the form it's placed on, without having compile-time knowledge of the form itself? Sounds a lot like a TButton that doesn't know what to do with the form it's on when you click it, and the solution is the same: use an event handler. Add an OnChangeMesh (or something like that) event property to your frame, and have your form assign the appropriate method when it creates the frames.

Mason Wheeler
Thank you very much for the response. I now understand that event handlers will allow me to call subroutines of the parent form from that form's frame, and that is a solution to my problem as i stated it. I would like to know if it is additionally possible to alter data fields of the parent form from the daughter frames. E.G. if i make a slice of the mesh in one of the frames, I would like to update the viewable limits of the mesh, which is a property of the parent form.
Nicholas
There's no limit to the number of events that you can have. You can have your frame raise an event and then have the parent form read back from the frame, update properties accordingly and then potentially propogate those property changes to the other frames if required.
Jenakai
+3  A: 

You could use a subscription structure. Maintain a global list of the view-frames. If the frames need to update simply loop over this list and call the updae procedure for eacht of the frames. This allows you to have 1,2 or 100 frames update if something has changed.

If you want to go all OOP and be really happy about it: this is the observer pattern.

http://en.wikipedia.org/wiki/Observer_pattern

birger
+4  A: 

Another option may be to define an interface that the parent form implements. It should have all the properties and methods that you want to access from your child frame, something like:

ImyFormInterface=interface
['{08BD9B3C-C48E-47B7-AE67-279277C7E024}']
  function GetValue1: integer;
  function GetValue2: integer;
  procedure SetValue1(val: integer);
  procedure SetValue2(val: integer);

  procedure SomeMethod;
  function GetSomeValue: integer;


  property Value1: integer read GetValue1 write SetValue1;
  property Value2: integer read GetValue2 write SetValue2;
end;

Then make your main form implement that interface:

TForm1 = class(TForm, ImyFormInterface)
private
  { Private declarations }
public
  // Implement ImyFormInterface
  function GetValue1: integer;
  function GetValue2: integer;
  procedure SetValue1(val: integer);
  procedure SetValue2(val: integer);

  procedure SomeMethod;
  function GetSomeValue: integer;
public
  { Public declarations }
end;

Then in your frame you can use something like:

procedure Tframe1.Button1Click(Sender: TObject);
var pform: TcustomForm;
i: ImyFormInterface;
begin
  pform:=GetParentForm(self);
  if (pform.GetInterface(ImyFormInterface, i)) then
  begin
    i.SomeMethod;

    i.Value1:=i.Value1+10;

    Self.SomeProperty:=i.GetSomeValue;
  end;
end;

Now if you inherit from your parent form it will all still work because you will still get the interface. Also, you could put your frames on an entirely new form and as long as that new form implements the interface then it will work there too.

Jenakai
A: 

A final solution might be to check out visual form/frame inheritance.

It is possible to derive forms from a baseform and frames from a baseframe. Add virtual methods to the baseframe and override them in the inherited versions.

Marco van de Voort