tzigi
asked on
How to Show a Child Form while the Application is Minimized
Greetings,
I have a program that on an event it shows a form.
If I minimize the Application, the form will not show until I click the Application Title in the taskbar.
Can I show or keep a child form visible while the Application is minimized ?
I have a program that on an event it shows a form.
If I minimize the Application, the form will not show until I click the Application Title in the taskbar.
Can I show or keep a child form visible while the Application is minimized ?
to add to Ivanov_G,
If you assign your own event to the global application, then no matter where you minimize from in the application,
the event will be called.....
Application.OnMinimize := AppMinimize;
procedure AppMinimize;
begin
Form2 := TForm2.Create(nil);
Form2.FormStyle := fsStayOnTop;
Form2.ShowModal;
end;
// NOTE : remove Form2 from Auto-Create Forms in Project / Options / Forms
SHane
If you assign your own event to the global application, then no matter where you minimize from in the application,
the event will be called.....
Application.OnMinimize := AppMinimize;
procedure AppMinimize;
begin
Form2 := TForm2.Create(nil);
Form2.FormStyle := fsStayOnTop;
Form2.ShowModal;
end;
// NOTE : remove Form2 from Auto-Create Forms in Project / Options / Forms
SHane
Hello
If you are using windows 2000 then showing the form on a minimized application becomes tricky, Windows 98/2000 doesn't want to foreground a window when some other window has keyboard focus, so even if you restore your form with the methods described earlier in my own experince they still would remind in the background of the currently active application. So unless your desktop was totally minimized it wouldnt work the way you want it to, somehow fsStayOnTop doesnt help either...
I found the following procedure to achive total frontness on all systems
I cant take the credit as i found it as a snipet long time ago, the original author did a great job though
function ForceForeground(AppHandle: HWND): boolean;
const
SPI_GETFOREGROUNDLOCKTIMEO UT = $2000;
SPI_SETFOREGROUNDLOCKTIMEO UT = $2001;
var
ForegroundThreadID: DWORD;
ThisThreadID : DWORD;
timeout : DWORD;
OSVersionInfo : TOSVersionInfo;
Win32Platform : Integer;
begin
if IsIconic(AppHandle) then ShowWindow(AppHandle, SW_RESTORE);
if (GetForegroundWindow = AppHandle) then Result := true else
begin
Win32Platform := 0;
OSVersionInfo.dwOSVersionI nfoSize := SizeOf(OSVersionInfo);
if GetVersionEx(OSVersionInfo ) then Win32Platform := OSVersionInfo.dwPlatformId ;
{ Windows 98/2000 doesn't want to foreground a window when some other window has keyboard focus}
if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (OSVersionInfo.dwMajorVers ion > 4)) or
((Win32Platform = VER_PLATFORM_WIN32_WINDOWS ) and ((OSVersionInfo.dwMajorVer sion > 4) or
((OSVersionInfo.dwMajorVer sion = 4) and (OSVersionInfo.dwMinorVers ion > 0)))) then
begin
Result := false;
ForegroundThreadID := GetWindowThreadProcessID(G etForegrou ndWindow,n il);
ThisThreadID := GetWindowThreadPRocessId(A ppHandle,n il);
if AttachThreadInput(ThisThre adID, ForegroundThreadID, true) then
begin
BringWindowToTop(AppHandle );
SetForegroundWindow(AppHan dle);
AttachThreadInput(ThisThre adID, ForegroundThreadID, false);
Result := (GetForegroundWindow = AppHandle);
end;
if not Result then
begin
SystemParametersInfo(SPI_G ETFOREGROU NDLOCKTIME OUT, 0, @timeout, 0);
SystemParametersInfo(SPI_S ETFOREGROU NDLOCKTIME OUT, 0, TObject(0), SPIF_SENDCHANGE);
BringWindowToTop(AppHandle );
SetForegroundWindow(AppHan dle);
SystemParametersInfo(SPI_S ETFOREGROU NDLOCKTIME OUT, 0, TObject(timeout), SPIF_SENDCHANGE);
Result := (GetForegroundWindow = AppHandle);
if not Result then
begin
ShowWindow(AppHandle,SW_HI DE);
ShowWindow(AppHandle,SW_SH OWMINIMIZE D);
ShowWindow(AppHandle,SW_SH OWNORMAL);
BringWindowToTop(AppHandle );
SetForegroundWindow(AppHan dle);
end;
end;
end else
begin
BringWindowToTop(AppHandle );
SetForegroundWindow(AppHan dle);
end;
Result := (GetForegroundWindow = AppHandle);
end;
end;
You would still have to create the form using
Form2 := TForm2.Create(Application) ;
Form2.ShowModal;
Form2.Free;
and in the create event of form2 call the function about to put your form on top of everything else
ForceForeground(Form2.Hand le); or just ForceForeground(Handle);
also if you use form2.show and create form2 automatically then i guess you can just call ForceForeground(Form2.Hand le); when your special event occurs.
Ekim
If you are using windows 2000 then showing the form on a minimized application becomes tricky, Windows 98/2000 doesn't want to foreground a window when some other window has keyboard focus, so even if you restore your form with the methods described earlier in my own experince they still would remind in the background of the currently active application. So unless your desktop was totally minimized it wouldnt work the way you want it to, somehow fsStayOnTop doesnt help either...
I found the following procedure to achive total frontness on all systems
I cant take the credit as i found it as a snipet long time ago, the original author did a great job though
function ForceForeground(AppHandle:
const
SPI_GETFOREGROUNDLOCKTIMEO
SPI_SETFOREGROUNDLOCKTIMEO
var
ForegroundThreadID: DWORD;
ThisThreadID : DWORD;
timeout : DWORD;
OSVersionInfo : TOSVersionInfo;
Win32Platform : Integer;
begin
if IsIconic(AppHandle) then ShowWindow(AppHandle, SW_RESTORE);
if (GetForegroundWindow = AppHandle) then Result := true else
begin
Win32Platform := 0;
OSVersionInfo.dwOSVersionI
if GetVersionEx(OSVersionInfo
{ Windows 98/2000 doesn't want to foreground a window when some other window has keyboard focus}
if ((Win32Platform = VER_PLATFORM_WIN32_NT) and (OSVersionInfo.dwMajorVers
((Win32Platform = VER_PLATFORM_WIN32_WINDOWS
((OSVersionInfo.dwMajorVer
begin
Result := false;
ForegroundThreadID := GetWindowThreadProcessID(G
ThisThreadID := GetWindowThreadPRocessId(A
if AttachThreadInput(ThisThre
begin
BringWindowToTop(AppHandle
SetForegroundWindow(AppHan
AttachThreadInput(ThisThre
Result := (GetForegroundWindow = AppHandle);
end;
if not Result then
begin
SystemParametersInfo(SPI_G
SystemParametersInfo(SPI_S
BringWindowToTop(AppHandle
SetForegroundWindow(AppHan
SystemParametersInfo(SPI_S
Result := (GetForegroundWindow = AppHandle);
if not Result then
begin
ShowWindow(AppHandle,SW_HI
ShowWindow(AppHandle,SW_SH
ShowWindow(AppHandle,SW_SH
BringWindowToTop(AppHandle
SetForegroundWindow(AppHan
end;
end;
end else
begin
BringWindowToTop(AppHandle
SetForegroundWindow(AppHan
end;
Result := (GetForegroundWindow = AppHandle);
end;
end;
You would still have to create the form using
Form2 := TForm2.Create(Application)
Form2.ShowModal;
Form2.Free;
and in the create event of form2 call the function about to put your form on top of everything else
ForceForeground(Form2.Hand
also if you use form2.show and create form2 automatically then i guess you can just call ForceForeground(Form2.Hand
Ekim
ASKER
Greetings,
The suggested sollutions work.
The only problem now is that if I MANUALLY minimize Form1, Form2 will not remain on screen.
I cannot use (of course) showmodal, cause then I will not be able to minimize Form1.
Regards,
Tzigi
The suggested sollutions work.
The only problem now is that if I MANUALLY minimize Form1, Form2 will not remain on screen.
I cannot use (of course) showmodal, cause then I will not be able to minimize Form1.
Regards,
Tzigi
handle WM_SYSCOMMAND with wParam = SC_MINIMIZE. Thus you will know when Form1 is minimized and you can do your stuff there
--------------------------
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TForm1 = class(TForm)
private
{ Private declarations }
procedure OnMinimize (var Msg : TMessage); message WM_SYSCOMMAND;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
{ TForm1 }
procedure TForm1.OnMinimize(var Msg: TMessage);
begin
if Msg.WParam = SC_MINIMIZE then
ShowMessage('Minimize');
end;
end.
hello tzigi. , , I did a program where I wanted a small information form, to pop up (show) while my programm was minimized,
but no matter what I tried, no Forms will show when the app is minimized, this is not a delphi thing, this is a windows system (API) thing. When a program is minimized, the system will not allow any windows (forms) associated with the program (TApplication in the case of delphi) to show, even if you set them to visible. So, for another program , , where I wanted persistent forms (not hide for minimized) I had to go a different way, I wish it was as easy as Ivanov_G says, but it was not for me. I had to catch the Forms syscommand and the application's syscommand stuff and some other messages as well
Some code - -
first the dpr file
program DllFrame;
uses
Forms,
DllFrame1 in 'DllFrame1.pas' {Form1},
SecondForm in 'SecondForm.pas' {Form2};
{$R *.RES}
begin
Application.Initialize;
Application.Title := 'Frame Dll';
Application.CreateForm(TFo rm1, Form1);
Application.CreateForm(TFo rm2, Form2);
Application.Run;
end.
- - - - - - - - - - - - - - - -
you WILL NOT need to change the DPR program file at all, , , , ,
I include this just to show you that I Create the Form2 from the start, not later.
- - - - - - - - - - - - - - - - - - -
I have a TApplicationEvents on the main form
CODE FOR Main Form1 - - -
TForm1 = class(TForm)
ApplicationEvents1: TApplicationEvents;
procedure FormCreate(Sender: TObject);
procedure ApplicationEvents1Message( var Msg: tagMSG;
var Handled: Boolean);
private
{ Private declarations }
procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
var
Form1: TForm1;
implementation
{$R *.DFM}
uses SecondForm; // include you Form2 unit here
procedure TForm1.FormCreate(Sender: TObject);
begin
{ the sys menu ID should NOT have any $F bits in it, , I use
$F0, but you can use $F10 to $F0, do not use the last 0 of the Hex, let it stay 0. .
this is created grayed, disabled, in the top position}
InsertMenu(GetSystemMenu(A pplication .Handle, False), 0,
MF_BYPOSITION or MF_STRING or MF_GRAYED, $F0, 'Show Main Window');
// change 'Show Main Window' to your own menu text
end;
procedure TForm1.ApplicationEvents1M essage(var Msg: tagMSG;
var Handled: Boolean);
begin
Handled := False;
{you will need to get the Application's WM_SYSCOMMAND message}
if Msg.hwnd = Application.Handle then
if (Msg.message = WM_SYSCOMMAND) then
if (Msg.wParam and $FFF0) = $F0 then //$F0 is your menu Command ID
begin
if IsIconic(Application.Handl e) then
Application.Restore;
Show; // Main Form will show
EnableMenuItem(GetSystemMe nu(Applica tion.Handl e, False), $F0, MF_BYCOMMAND or MF_GRAYED);
end else
if ((Msg.wParam and $FFF0) = SC_MINIMIZE) and Visible then
begin
{ I'm NOT sure this is the functionallity you would want? ?
you may want the TaskBar or System Menu to really Minimize?
if so, , then leave out this Msg.wParam and $FFF0) = SC_MINIMIZE test}
EnableMenuItem(GetSystemMe nu(Applica tion.Handl e, False), $F0, MF_BYCOMMAND or MF_ENABLED);
Hide; // Main Form will hide
Handled := True;
Exit;
end;
end;
procedure TForm1.WMSysCommand(var Message: TWMSysCommand);
begin
{you will need to Hide main form instead of minimize app, if I minimize the app,
then I CAN NOT show any form at all}
with Message do
if (CmdType and $FFF0 = SC_MINIMIZE) and Assigned(Form2) and Form2.Visible then
begin
EnableMenuItem(GetSystemMe nu(Applica tion.Handl e, False), $F0, MF_BYCOMMAND or MF_ENABLED);
Hide; // hide this main Form
end else
inherited;
end;
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CODE FOR Form2
type
TForm2 = class(TForm)
private
{ Private declarations }
procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
var
Form2: TForm2;
implementation
{$R *.DFM}
uses DllFrame1; // Main Form1 unit
procedure TForm2.WMSysCommand(var Message: TWMSysCommand);
begin
{if Form 2 is the Only form visible, I would change the
syscommand}
with Message do
begin
if (Assigned(Form1)) and Form1.Visible then
begin
{if Form1 is up then do nothing}
inherited;
Exit;
end;
if (CmdType and $FFF0 = SC_MINIMIZE) then
begin
Application.Minimize;
{ you may want different action here, but this is what I needed}
end else
if (CmdType and $FFF0 = SC_CLOSE) then
Application.Terminate // Form2 as the Main Form, close Application
else inherited;
end;
end;
= = = = = = = = = = = = = = = = = = = = = = = = = = ==
this did what I wanted to do, but this takes it OUT of the usuall delphi methods, so some other things (show and hide?) may not do as normal delphi would do
ask questions if you need more info
but no matter what I tried, no Forms will show when the app is minimized, this is not a delphi thing, this is a windows system (API) thing. When a program is minimized, the system will not allow any windows (forms) associated with the program (TApplication in the case of delphi) to show, even if you set them to visible. So, for another program , , where I wanted persistent forms (not hide for minimized) I had to go a different way, I wish it was as easy as Ivanov_G says, but it was not for me. I had to catch the Forms syscommand and the application's syscommand stuff and some other messages as well
Some code - -
first the dpr file
program DllFrame;
uses
Forms,
DllFrame1 in 'DllFrame1.pas' {Form1},
SecondForm in 'SecondForm.pas' {Form2};
{$R *.RES}
begin
Application.Initialize;
Application.Title := 'Frame Dll';
Application.CreateForm(TFo
Application.CreateForm(TFo
Application.Run;
end.
- - - - - - - - - - - - - - - -
you WILL NOT need to change the DPR program file at all, , , , ,
I include this just to show you that I Create the Form2 from the start, not later.
- - - - - - - - - - - - - - - - - - -
I have a TApplicationEvents on the main form
CODE FOR Main Form1 - - -
TForm1 = class(TForm)
ApplicationEvents1: TApplicationEvents;
procedure FormCreate(Sender: TObject);
procedure ApplicationEvents1Message(
var Handled: Boolean);
private
{ Private declarations }
procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
var
Form1: TForm1;
implementation
{$R *.DFM}
uses SecondForm; // include you Form2 unit here
procedure TForm1.FormCreate(Sender: TObject);
begin
{ the sys menu ID should NOT have any $F bits in it, , I use
$F0, but you can use $F10 to $F0, do not use the last 0 of the Hex, let it stay 0. .
this is created grayed, disabled, in the top position}
InsertMenu(GetSystemMenu(A
MF_BYPOSITION or MF_STRING or MF_GRAYED, $F0, 'Show Main Window');
// change 'Show Main Window' to your own menu text
end;
procedure TForm1.ApplicationEvents1M
var Handled: Boolean);
begin
Handled := False;
{you will need to get the Application's WM_SYSCOMMAND message}
if Msg.hwnd = Application.Handle then
if (Msg.message = WM_SYSCOMMAND) then
if (Msg.wParam and $FFF0) = $F0 then //$F0 is your menu Command ID
begin
if IsIconic(Application.Handl
Application.Restore;
Show; // Main Form will show
EnableMenuItem(GetSystemMe
end else
if ((Msg.wParam and $FFF0) = SC_MINIMIZE) and Visible then
begin
{ I'm NOT sure this is the functionallity you would want? ?
you may want the TaskBar or System Menu to really Minimize?
if so, , then leave out this Msg.wParam and $FFF0) = SC_MINIMIZE test}
EnableMenuItem(GetSystemMe
Hide; // Main Form will hide
Handled := True;
Exit;
end;
end;
procedure TForm1.WMSysCommand(var Message: TWMSysCommand);
begin
{you will need to Hide main form instead of minimize app, if I minimize the app,
then I CAN NOT show any form at all}
with Message do
if (CmdType and $FFF0 = SC_MINIMIZE) and Assigned(Form2) and Form2.Visible then
begin
EnableMenuItem(GetSystemMe
Hide; // hide this main Form
end else
inherited;
end;
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CODE FOR Form2
type
TForm2 = class(TForm)
private
{ Private declarations }
procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
var
Form2: TForm2;
implementation
{$R *.DFM}
uses DllFrame1; // Main Form1 unit
procedure TForm2.WMSysCommand(var Message: TWMSysCommand);
begin
{if Form 2 is the Only form visible, I would change the
syscommand}
with Message do
begin
if (Assigned(Form1)) and Form1.Visible then
begin
{if Form1 is up then do nothing}
inherited;
Exit;
end;
if (CmdType and $FFF0 = SC_MINIMIZE) then
begin
Application.Minimize;
{ you may want different action here, but this is what I needed}
end else
if (CmdType and $FFF0 = SC_CLOSE) then
Application.Terminate // Form2 as the Main Form, close Application
else inherited;
end;
end;
= = = = = = = = = = = = = = = = = = = = = = = = = = ==
this did what I wanted to do, but this takes it OUT of the usuall delphi methods, so some other things (show and hide?) may not do as normal delphi would do
ask questions if you need more info
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Slick812, you have earned your points.
Just one clarification, can you repost the fixed procedure TForm2.WMSysCommand(var Message: TWMSysCommand); ?
Thanks a lot !,
Tzigi
Just one clarification, can you repost the fixed procedure TForm2.WMSysCommand(var Message: TWMSysCommand); ?
Thanks a lot !,
Tzigi
I was look at my post to check it and thought I saw a misteak? but I lost count of the begin - - end; combinations and posted a correction
but the correction is Incorrect ! ! ! Duhhhhhhhhhhhhhhhhhhhh !
I shoud be sleeping instead of coding, :-) Ha ha
so the original code is correct and the new correction code is not needed
but the correction is Incorrect ! ! ! Duhhhhhhhhhhhhhhhhhhhh !
I shoud be sleeping instead of coding, :-) Ha ha
so the original code is correct and the new correction code is not needed
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
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
begin
Application.Minimize;
Form2 := TForm2.Create(nil);
Form2.FormStyle := fsStayOnTop;
Form2.ShowModal;
end;
end.
// NOTE : remove Form2 from Auto-Create Forms in Project / Options / Forms