Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

My detail form is hidden behind main form when calling the TsaveDialog

Tags:

delphi

My application is based of a MainForm, DetailForms and DialogForms. On the taskbar I can see the MainFormButton and also the DetailForms. Therefore I use:

procedure <DetailForm>.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
  Params.WndParent:= GetDesktopWindow;  
end; 

I use delphi 2010 and I've set Application.MainFormOnTaskbar:= True; When I use PromptForFileName or TSaveDialog in the Detailform then the DetailForm go behind the Mainform. The DetailForm come back after closing the dialog.

When I use DialogForm (Showmodal of TForm with property PopupMode: pmAuto) then my DetailForm is stay between the main and dialog. How can I force the TSaveDialog like a showmodal with property PopupMode: pmAuto or how can i prevent that my detailform goes behind the mainform

Demo:

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};

  {$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ImgList, ActnList;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  oForm: TForm;
begin
  oForm:= Unit2.TForm2.Create(Self);
  oForm.Show;
end;
end.

unit Unit2;

interface

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

type
  TForm2 = class(TForm)

    SaveDialog1: TSaveDialog;
    procedure cxButton1Click(Sender: TObject);
  private
  protected
    procedure CreateParams(var Params: TCreateParams); override;
        { Private declarations }

  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

{ TForm2 }

procedure TForm2.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
  Params.WndParent:= 0;   // --> Testing
end;

procedure TForm2.cxButton1Click(Sender: TObject);
begin
  self.SaveDialog1.execute();
end;

end.
like image 587
Ravaut123 Avatar asked Jan 24 '13 13:01

Ravaut123


Video Answer


1 Answers

Step 1 is that you must not make the desktop window the owner of your form. Raymond Chen explains why not.

To really understand what's happening you need to read Window Features on MSDN to get a clearer understanding of window ownership. And be very careful that window ownership is a concept completely unrelated to Delphi component ownership. In Delphi terms, window ownership is controlled by the PopupParent property.

As has been clarified in comments, you want both forms to be unowned, top-level windows. The main form automatically is that. For the details form you need to set WndParent to 0 and that's it:

procedure <DetailForm>.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.WndParent := 0;
end; 

The final step is to make sure that the save dialog is owned properly. To do that specify the owner when you call Execute:

Self.SaveDialog1.Execute(Self.Handle);

So, in summary you need to make three changes:

  1. Set the detail form's WndParent to 0.
  2. Remove the WS_EX_APPWINDOW extended style, it is not needed for an unowned top-level window.
  3. Pass the detail form's handle when calling Execute on the save dialog.

Update

It turns out that you are using XP, and the Delphi code that shows the file dialog is rubbish. Although you pass a handle to the Execute method, that is ignored and the main window handle is used as the dialog's owner. And that's why the main window comes to the front.

You can get around this by setting Application.ModalPopupMode to pmAuto. You should probably set this in your .dpr file.

Read more about this here: http://blogs.embarcadero.com/abauer/2005/09/30/21517

like image 88
David Heffernan Avatar answered Oct 07 '22 00:10

David Heffernan