how to create MDI form in delphi - delphi

How can I solve this problem "Cannot Create Forms. No MDI forms are currently active". I want to make a simple program that wod require a Login Form before it can acess the main form. I got three forms: Main Form (MDI Form), Form2 (MDIChild) and Login Form (Normal). Login form would appear first then the Main Form, then when I try to call on Form 2 from the Main form, an error would display "Cannot Create Forms. No MDI forms are currently active".
I am using Delphi 7 on windows XP. I'm a beginner. Thank you very much sir.

It sounds like you're letting your LoginForm be auto-created, and it's being created first. This won't work, because the first form created by Application.CreateForm in the project file becomes the Application.MainForm. In order by be an MDI application, the MainForm must be a MDI parent window.
The solution is usually to not auto-create your login form, and instead create it yourself. To do so, you need to edit your .dpr file (Project->View Source from the IDE's main menu).
Your project source should look something like this now (obviously, using your classes in the Application.CreateForm calls):
begin
Application.Initialize;
Application.CreateForm(TLoginForm, LoginForm);
Application.CreateForm(TMainForm, MainForm);
Application.CreateForm(TChildForm, ChildForm);
Application.Run;
end.
You need to modify it so that the LoginForm isn't created first.
var
LoginOK: Boolean = False;
begin
LoginForm := TLoginForm.Create(nil);
try
// Show login form. When it closes, see if login worked.
LoginForm.ShowModal;
LoginOK := LoginForm.CanLogin; // However you know login is OK or not here
finally
LoginForm.Free;
end;
if not LoginOK then
Halt; // Login failed - terminate application.
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
{
I normally do not auto-create anything but the main form
and maybe a datamodule (which you **can** autocreate first -
it is not a form), but a MDI application is pretty useless
without at least one open child window, IMO.
}
Application.CreateForm(TChildForm, ChildForm);
Application.Run;
end.

Related

Disable Application.CreateForm with new form

I have a function which checks the settings and permissions before the start of the application, and if everything goes through, it selects what version to run and accordingly changes the main form.
function SomeControlFunction: Boolean;
var
lMainForm : TForm;
begin
if SomePermission then
Application.CreateForm(TUForm1, lMainForm)
else
Application.CreateForm(TUForm2, lMainForm);
end;
Project.dpr
Application.Initialize;
if SomeControlFunction then
Application.Run;
Unfortunately every time I create a new form in the project, it automatically adds to Project.dpr and I have to delete it every time. Is there any way to disable this behavior or is the whole process wrong and I should run the application differently?
Application.Initialize;
if SomeControlFunction then
Application.CreateForm(TUNewForm, UNewForm);
Application.Run;
There is a work around to prevent the IDE from changing the dpr-file in that way.
It seems that the Delphi IDE will explicitly look for places where the global variable Application from Vcl.Forms is used in the dpr-file and accordingly add the CreateForm calls.
The standard template code in the dpr-file looks like this:
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
<-- new forms will be added here automatically
Application.Run;
If you use an 'alias' variable - lets say App - instead, the IDE will not interfere. Replace your existing code in the dpr-file with following:
var
App: TApplication;
begin
App := Application;
App.Initialize;
if SomeControlFunction then
App.Run;
end.
Adding new Forms won't automatically add CreateForm calls in your dpr-file now.
Is there any way to disable this behavior?
In the options dialog, select the Form Designer node, and uncheck the Auto create forms & data modules option.
The documentation for this option states:
Toggles whether or not to automatically create forms. When unchecked, forms added to the project after the first one are put into the Available Forms list rather than the Auto Create list. You can change where each form is listed by choosing Project > Options > Forms.
What the documentation does not tell you is that this option is ignored when you add a new form to a project that does not already contain at least one auto-create form. So it's probably not going to be very useful for you.
By the way, SomeControlFunction does not set the return value.

Calling Show() of embedded form should show parent form

I use embedded forms in my application and I was trying something like this:
At designtime the form is a normal form which don't know anything about embedding/docking.
With a ButtonClick I can make the form visible by calling the Show() method of the form.
At runtime it can happen that the form gets docked into another form and becomes an embedded form.
When I press the Button for showing the form again (which is now embedded) nothing happens because
I have to call Show() for the form which contains the embedded form now.
I am lookin for a method to force showing the parent form when the Show() method of the embedded form is called. I could handle this by checking the existance of a parent form before calling Show() but I don't want to include this specific handling.
I would prefer to do this handling in the parent form wich gets notified when a form is docked.
The Show() method only sets the Visible property to true (RAD Studio Help), so I don't think that a message is fired ...?
Do you know a method to realize something like this?
Edit
I want to put some information about my application because I guess that it is more a designing problem than a programming problem.
The application uses several plugins to adapt to the connected hardware. The exe provides a drag&dock environment and contains a base class for dockable forms. The plugins don't have any knowledge about the docking implementation. By creating a dockable form and embedding a form from the plugin the plugin form becomes dockable. This is the reason why I want do get the parent form shown when somewhere the method Show() of the embedded form is called.
You could create a common ancestor for your embedded forms or even for all forms in the application, and then derive your forms from it:
type
TEmbeddedForm = class(TForm)
public
procedure Show;
end;
procedure TEmbeddedForm.Show;
var
ParentForm: TCustomForm;
begin
inherited Show;
ParentForm := GetParentForm(Self);
if ParentForm <> Self then
begin
// Form is Embedded
Update;
ParentForm.Show;
// You might alternatively consider to send custom
// message to the Parent form, and let it decide what to do e.g.
// SendMessage(ParentForm.Handle, CM_MY_EMBEDED_FORM_SHOW, 0, 0);
end;
end;
Then when you call:
procedure TForm1.Button1Click(Sender: TObject);
begin
// MyEmbeddedForm is derived from TEmbeddedForm
MyEmbeddedForm.Align := alClient;
MyEmbeddedForm.BorderStyle := bsNone;
MyEmbeddedForm.Parent := Form3.Panel1;
MyEmbeddedForm.Show;
end;
Form3 is showing.
Another option (which I only confirmed with Spy++) is to intercept WM_CHILDACTIVATE or WM_WINDOWPOSCHANGING in the TEmbeddedForm. it is sent to it when the child form is calling TEmbeddedForm.Show, and act accordingly i.e. GetParentForm(Self).Show.
Use SetFocus instead of Show on the embedded form.
This will enforce showing of the parent form too.

Switching forms in delphi [duplicate]

This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Delphi application with login / logout - how to implement?
I am trying to switch between two forms in my delphi application, first, a login screen appears and then the main form of the application appears.
I am using formx.hide and .show to switch between the forms.
eg.
//after password checking
form1.hide;
form2.show;
The second form appears, but cannot be interacted with, as if it is disabled.
Why would it be doing this?
Since you have not provided any code, we have to guess at what your problem is. So here goes.
Forms get disabled when other forms are shown modally, and then re-enabled when the modal form is closed. So most likely you show the login form modally and then hide it rather than close. To close the modal form you need to set the modal form's ModalResult property. If you hide rather than close, then the main form will still be disabled. The key is that you must properly close the modal form before the main form can become usable.
Typically for an app with an initial login form you organise your application's .dpr file like this:
var
LoginForm: TLoginForm;
MainForm: TMainForm;
LoginSucceeded: Boolean;
begin
Application.Initialize;
LoginForm := TLoginForm.Create(nil);
try
LoginForm.ShowModal;
LoginSucceeded := LoginForm.Successful;
finally
LoginForm.Free;
end;
if LoginSucceeded then
begin
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end;
end;
The first form created using Application.CreateForm becomes your applications's main form. When the main form is closed, the entire application goes down with it. In my opinion, you should use Application.CreateForm only for creating the main form. Any other forms can be created using the TMyForm.Create syntax. If you follow that policy then you don't need to worry about which order your forms are created in.
Is the main form actually the first form to be created? The first form to be created with Application.CreateForm (check the source of your .dpr file), is regarded the main form. Closing that form essentially closes the application.

Make 2 forms able to overlap each other?

I would like to have a seperate form that shows "along" with my main form, so it does not overlap the main form.
Here's an example:
Notice how the main program, overlaps the log? I can't figure out how to do that in Delphi.
Thanks!
The answers to this question lie in the very useful Window Features MSDN topic.
The pertinent information is:
An overlapped or pop-up window can be
owned by another overlapped or pop-up
window. Being owned places several
constraints on a window.
An owned window is always above its owner in the z-order.
The system automatically destroys an owned window when its owner is
destroyed.
An owned window is hidden when its owner is minimized.
The main form in your app is the owner (in Windows terminology rather than Delphi terminology) of the other popup windows. The first bullet point above implies that the owned windows always appear above the main form (the owner).
Try creating an app with 3 forms and show them all. The .dpr would look like this:
program OwnedWindows;
uses
Forms,
Main in 'Main.pas' {MainForm},
Popup1 in 'Popup1.pas' {PopupForm1},
Popup2 in 'Popup2.pas' {PopupForm2};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TMainForm, Main);
Application.CreateForm(TPopupForm1, PopupForm1);
Application.CreateForm(TPopupForm2, PopupForm2);
PopupForm1.Show;
PopupForm2.Show;
Application.Run;
end.
You will see that the main form is always underneath the other two forms, but these other owned forms can be above or below each other. When you minimize the main form they all disappear.
You could if you want make all of your forms top-level unowned windows:
procedure TPopupForm1.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WndParent := 0;
end;
And like wise for TPopupForm2 in my example. This would result in all 3 windows having taskbar buttons.
One other approach is to revert to the pre-Vista way of things and make the Application's hidden window be the top-level owner window. You do this by making sure that Application.MainFormOnTaskbar is False. Skip all the CreateParams code and you'll now have a single window on the taskbar and any of your windows can be above any other because the top-level owner window is the hidden window Application.Handle. Of course the downside is that you lose your Aero Peek.
So, I guess what you need to do is to make the main form appear on the taskbar as usual, but ensure that the other forms are not owned (in the Windows sense) by the main form. But they need to be owned to avoid having them in the taskbar. So you can make the hidden application window be the owner using the CreateParams method, like so:
procedure TOverlappedPopupForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.WndParent := Application.Handle;
end;
Although you state otherwise in the comments, when I do this I find that the popup form is indeed hidden when I minimize the main form. And it is shown again when the main form is restored. Thus I think this does solve your problem completely.
I haven't got Delphi open now, but would setting
mainform.formstyle := fsStayOnTop
and show the child form with
childform.show;
work?
or else try using SetWindowPos() and setting the hWndInsertAfter property to something like HWND_TOPMOST on the main form

Why would something fail in FormCreate, but work fine in FormShow?

I'm using Delphi 7. When I try to create an object in FormCreate, it fails (actually it just hangs). When I try to do the same thing in FormShow, it works. Please note, I'm not talking about creating a visual component like a TEdit. It's a database abstraction object. Any ideas why this might happen? Are there any guidelines about this topic?
1) The reason is because on FormCreate, the handle to Form is not created yet.
If your database object needs a form handle, do this:
Self.HandleNeeded; // on FormCreate time.
2) The other reason is maybe your database component needs to be connected and it's only connected on DFM?
My first guess is that you're accessing a DataModule hasn't been created yet. If your project's source looks like the following:
begin
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TDataModule1, DataModule1);
Application.Run;
end.
And your TForm1.FormCreate looks like the following:
begin
DataModule1.AddUsersToStringList(Self.ComboBox1.Items);
end;
Then FormCreate going to fail because it's is being run as part of the Application.CreateForm(TForm1, Form1); line, and your Data Module hasn't been created yet.
There's 2 solutions:
Defer your processing/initialization until after all the forms and data modules have been created.
Create all the data modules before creating any of your forms. The Application's "Main Form" in Delphi is the first TCustomForm descendant created by Application.CreateForm, not the first object.

Resources