Subforms - basics

Hey,

What do I need to do to load a form within another form?  I found this nice tutorial at http://www.delphipages.com/tips/thread.cfm?ID=6, but it doesn't seem to explain things enough so I can understand.

What I'm specifically looking for, is how to load a form within another form dymanically (ie, not necessarily when the program loads) as well as unload it at a later date.  It would also be nice to transfer data between the main form and subform.

Thanks
SebastionAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

tobjectpascalCommented:
Well unless you state the form not to be autocreated, it will be there anyway.

Delphi > File > New Form

Save the form as YourForm2 and press OK, now from your main form it's a simple case of going..

Form2.Show;

(or if you changed the name of the form, Somethingelse.Show);

But to make it truely Dynamic, you have To remove it from the list of forms, the easiest way would be to go to the Menu in Delphi

Project > Options

Auto CreateForms     |     Available Forms.

Form1
Form2


Move Form2 to Available Forms on the right.

Then on your main unit, go to the top, Add the unit name in this case if you don't save it, simply add unit2 at the uses at the top.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Unit2;


Like that, then make a button on your main form..

procedure TForm1.Button1Click(Sender: TObject);
Var
 YourForm: TForm2;
begin
 YourForm:=TForm2.Create(self);
 YourForm.Visible:=True;
 //YourForm.Free; //make sure you release the memory when you finished with it
end;

That's pretty much all there is to it.
0
SebastionAuthor Commented:
Hey tobjectpascal,

Unfortunatly, that was not what I had it mind.  From what you describe, it opens a new form window on the button click.  What I was looking for was to physically open the form within another form, so as to appear like one program.

For example, in Microsoft Access, this is achieved by using a subform.  In HTML, you could probably use a frame to load multiple webpages.  If I remember correctly, in Visual C# this is accomplished by using panels and user controls.  In Delphi though, I'm unsure.

I've played around abit with Frames, but I'm not sure that they are what I'm after.  Ultimately, I would like to have it so that the program has a menu bar up top, that continually changes what is displayed "down the bottom".  In other words, if the user is currently viewing housing information, but wanted to see undeveloped land info, they'll nagivate through the menu which in turn will refresh the main section of the program (ideally by switching out the housing form with the undeveloped land form), rather than open a new window to display the information.
0
tobjectpascalCommented:
Var
 YourForm: TForm2;
begin
 YourForm:=TForm2.Create(self);
 YourForm.Parent:=Self;
 YourForm.Visible:=True;
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

SebastionAuthor Commented:
Alright, but the subform is still movable around the main.  How do I lock this in a set location?  Also, is it possible to remove the title bar from the subform, since it looks out of place.

What would I need to do to send a variable from one form to another?
0
Slick812Commented:
I beleive that the TForm was not intended to be a "Child" (like a control, a TPanel) of another window, although it is easy enough to just set a TForms parent to a Form or other windowed control, , I have found that the Delphi TFrame, will give more control like functioning (especially for Tab and arrow-key focus change) than a TForm as a child control. So I would recomend you try to use the TFrame for what you describe. I beleive the TFrame was made to be a Form that is a child control, because they do not have a title bar.  You can access the variables of the "Public" section of a Frame or Form if you add it to your "uses" clause, hopefully the uses clause in the implementation section
0
SebastionAuthor Commented:
Hey Slick812,

Yea, a frame was my original idea, but when I tried to add a BDE Table to it, the program kept erroring out.  To be exact, I could add the DataSource and Table, but when I tried to add fields the Table, the program kept returning the error "Table1: Duplicate field name".  If I repeat the exact same process on a form though, in the exact same project, I receive no errors.  Is there something about frames that I do not know about?
0
Slick812Commented:
I am not sure of what your problem may or may not be? ?
But if I were to guess, I would think that you are referencing a variable (something of the Database or database conection) in your TFrame, that you have declared in your TForm, where your code works, and  the TFrame is not able to use that variable, you might try to place the unit name of your form (Form1 is the default) in the "uses" clause of your TFrame, and you need to be sure that that variable is not in a private or protected section.
0
mwbowmanCommented:

I'm actually doing something similar in my own application using another database.  Using the following code, my users are able to create Child Windows from the Main Application:

procedure TFormMain1.CreateChildForm(Sender: TObject);
var
  Child: TFormChild;
begin

  Child := TFormChild.Create(Application);
  Application.ProcessMessages;
  Child.Caption := 'Your caption goes here...';

end;

The Child Form contains all of the necessary database access/control objects.
0
SebastionAuthor Commented:
Slick812, the passing of variables is not really my main problem with frames, it's more a matter of creating a BDE Table, and adding fields to that object that causes the errors I mentioned above.  I did abit more playing around, and it seems that the problem *might* be because I am using a frame within a frame.  Take the following example:

The project has one form (MainForm), and 2 frames (Client, ClientDetails).  At the moment, MainForm only has a frame object on it, linking to the Client frame.  The Client frame has a frame object on it as well, linking to the ClientDetails frame.  If I were to add a BDE Table on the Client frame, everything works fine and I'm able to add fields to it's fields editor.  Go back a step (and remove the BDE Table from the Clients frame) and if I add a BDE Table to ClientDetails, and try to add fields, I get the same error mentioned above (duplicate field name).

I'm going to need to play around with it abit.


Hey mwbowman, maybe I'm missing some steps, but when I followed your code example the form still opens as a new window, rather than in the same window.  Is this what you intended?
0
SebastionAuthor Commented:
Also note that I've increased the points on this question, since oddly enough it doesn't appear to be as straight forward as I initially though.
0
mwbowmanCommented:

That's true, but in this case you can open many forms (with grids) dynamically, including different instances of the same database, which is what I offer my users.

Are you simply wanting to create the grid in during runtime?  if so, then using frames is probably the best way to go.
0
SebastionAuthor Commented:
mwbownman, unfortunatly this was not the plan I had with my program.  In a previous post in this question, tobjectpascal suggested a similiar approach to what you mentioned, but I thought I had already clarified my intentions back then.

My intent with this program is to try and make the "bottom three quarters" dymanically generated, to reflect the different sections that the user is able to nagivate to.  For example, even though the bottom "data area" (which is pretty much everything in the program except the main menu) main initially start on client details, if the user nagivates to the property section using the main menu, then the data area should change to accomodate this new set of information.

I have been playing around with frames these last couple of days.  I've managed to work it so that I do not need to have 2 levels of frames (ie to avoid the form --> frame --> frame setup) as in this scenario, the second frame cannot appear to have a BDE Table (unsure about ADO, never tested).  It's looking more and more like this is what I'll need to do...
0
SebastionAuthor Commented:
So that brings me to a question now, instead of how to pass variables between forms, how does one pass variables between frames?  A search on the Internet didn't bring up much tutorials along the lines of frames for Delphi (if any at all).  I've declared the frame in the uses section for the mainform, but I cannot seem to use any of it's custom procedures or variables, even though the procedures and variables are public?
0
Slick812Commented:
??? Don't quite get your question. . . . as far as I have ever seen and used TFrame, they have the same unit structure as a TForm and I beleive the same unit variable and procedure and property access rules as a TForm. . . In my way of thinking, a Delphi UNIT code page will always have the same access rules and methods for whatever the unit code may be for. . .
But to help you, here is some code from a Main Form Unit and a TFrame unit, the first is the example code for the Form, next is example code for the Frame - -

unit MainU;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, Menus, ComCtrls, ImgList, Buttons, { --> }    imFrameU; // imFrameU is Frame Unit, with this here, public variable can be accessed

type
  TMainForm = class(TForm)
     fra4Bit: TImageFrame;
     fra8Bit: TImageFrame;
     fra24Bit: TImageFrame;
     fra32Bit: TImageFrame;

  private
    { Private declarations }
    Frames: ARRAY[0..3] OF TImageFrame;



procedure TMainForm.FormCreate(Sender: TObject);
var
i: Integer;
begin
Frames[0] := fra4Bit; // all these frames are created automatically
Frames[1] := fra8Bit;
Frames[2] := fra24Bit;
Frames[3] := fra32Bit;

for i := 0 TO High(Frames) DO
  with Frames[i] DO
    begin
    Setup(CellDown, CellMove, CellUp, PaletteF);
    Dimension := (3 - (i MOD 3))* 16;
    ColorCode := i DIV 3;
    end;
end;


procedure TMainForm.ClearAll(Sender: TObject);
var
i: Integer;
begin
for i := 0 to High(Frames) do
  Frames[i].Clear;
end;



 = = = = = = = = = = = = = = = = = = = =
// below is some example code for the imFrameU unit


unit imFrameU;

type
  TImageFrame = class(TFrame)
    pbDraw: TPaintBox;

  private
    { Private declarations }
    fAdj: Integer;    // can NOT be accessed in MainU

  public
    { Public declarations }
// all variable and procedures below are accessible in MainU
    ColorCount: Integer;
    procedure Setup(Dim, Make, Undo: TCellEvent; P: TColorFrame); // additional frame
    procedure Clear;
    property Dimension: Integer read GetDimension write SetDimension default 32;


implementation

uses MainU; // with this here, I can access Public variables and procedures in the MainU, , in this unit code below
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
SebastionAuthor Commented:
Slick812, that's what I needed to know.  I should be able to hand things from here.  Thanks
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.