5
votes

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: Example

Notice how the main program, overlaps the log? I can't figure out how to do that in Delphi.

Thanks!

2
+1 to offset anonymous down-vote. - Sertac Akyuz
+1 also, this is a most excellent question - David Heffernan
I'm afraid I don't understand what you're struggling with? If you create a brand new application and add a second form, this is exactly what you get. You don't need to do anything special. Perhaps it might help if you explain what your application is doing that you're not happy about. - Disillusioned
@Craig: No, you don't get that. Create a new VCL forms application, and make the main window blue. Now, add a new form to the application; make this smaller and red. Finally, create an OnClick handler on the main form and do Form2.Show. You will notice that the new, red, form, will never be displayed behind the main, blue, form. So you really do need to to something special. - Andreas Rejbrand

2 Answers

10
votes

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.

-1
votes

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