1

I have an application with multiple forms and a separate taskbar button for each form.

Let's say form2 displays an OpenDialog, I click away to another maximized application covering the full screen area, then I go back to form2 by selecting it's taskbar button. Voila! The OpenDialog is hidden behind the other application I selected, and I have to click on the now non-accessible form2 to bring the dialog back to the front. This is really annoying and may confuse the user.

Here is some code to illustrate the issue:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

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

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.Show;
end;

end.
________________

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm2 = class(TForm)
    OpenDialog1: TOpenDialog;
    Button1: TButton;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
begin
  OpenDialog1.Execute;
end;

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

end.

Is it possible maybe to get the handle of the visible opendialog? It used to be possible, but with the new Vista style OpenDialog if I trap OnDialogShow the OpenDialog reverts back to the old style which is a no go for me now.

Any ideas?

Steve
  • 2,510
  • 4
  • 34
  • 53

2 Answers2

3

TOpenDialog.Execute() has an optional parameter that lets you specify a parent window that the dialog is not allowed to fall behind:

procedure TForm2.Button1Click(Sender: TObject);
begin
  OpenDialog1.Execute(Self.Handle);
end;

If you do not specify a parent window, the active Form's window is used if Application.ModalPopupMode is not pmNone, otherwise the Application.MainForm window is used instead.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 1
    Will not quite help because you'll be able to bring form1 to front this time (tested) as form2 has no ownership relation with form1. – Sertac Akyuz Aug 13 '14 at 17:31
  • 1
    Which should be perfectly fine since Form1 and Form2 have their own taskbar buttons. Form2 will still be blocked by the open dialog, but the user can do things in other forms. Which is usually one of the main reasons for giving each Form its own taskbar button - to make them independent of each other. – Remy Lebeau Aug 13 '14 at 17:44
  • I agree with that. I might have misunderstood the question. – Sertac Akyuz Aug 13 '14 at 17:49
  • Sertac is right. Clicking on Form1 will not bring up the dialog, so this solution doesn't work in my case. Remy - there can be other uses for multiple taskbar buttons, ie.: opening multiple documents/windows with data. And if the opendialog is shown, it freezez the whole app, you can't do anything on Form1... – Steve Aug 13 '14 at 22:09
  • If Form2 is the parent of the dialog, then of course clicking on Form1 will not bring up the dialog, as Form1 has no concept of the dialog anymore. That is normal behavior. But the dialog is still running in the main thread and is a modal dialog, so it makes sense that Form1 would be blocked until the dialog is closed. – Remy Lebeau Aug 13 '14 at 22:20
  • I understand that this is the normal behaviour, but the question was how to get around it and bring the dialog into the front when the user clicks on Form1. I have a kind of a half solution though, I'll post it in a separate answer, maybe somebody can perfect that! – Steve Aug 14 '14 at 13:08
0

So I've figured out how to bring the dialog to the front, but there is still one problem: the focus is on Form2, not the dialog. If someone can tell me how to put the focus on the opendialog instead of Form2 and post it as an answer, I'll accept it.

Here are the code excerpts to add to the original:

type
  TForm1 = class(TForm)
  private
      procedure WMActivate(var Msg: TWMActivate); message WM_ACTIVATE;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  DialogFormHandle: HWnd;

...

procedure TForm1.WMActivate(var Msg: TWMActivate);
begin
    inherited;

    if DialogFormHandle <> 0 then
    begin
      BringWindowToTop(DialogFormHandle);
      exit;
    end;
end;

...

procedure TForm2.Button1Click(Sender: TObject);
begin
  try
    DialogFormHandle := Handle;
    OpenDialog1.Execute(Handle);
  finally
    DialogFormHandle := 0;
  end;
end;

Thanks!

Steve
  • 2,510
  • 4
  • 34
  • 53