Solved

How to Show a Child Form while the Application is Minimized

Posted on 2004-04-23
9
923 Views
Last Modified: 2010-04-05
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 ?
0
Comment
Question by:tzigi
  • 3
  • 2
  • 2
  • +2
9 Comments
 
LVL 12

Expert Comment

by:Ivanov_G
Comment Utility
unit Unit1;

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: TObject);
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
0
 
LVL 11

Expert Comment

by:shaneholmes
Comment Utility
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

0
 
LVL 3

Expert Comment

by:Kunfufaresi
Comment Utility
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_GETFOREGROUNDLOCKTIMEOUT = $2000;
SPI_SETFOREGROUNDLOCKTIMEOUT = $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.dwOSVersionInfoSize := 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.dwMajorVersion > 4)) or
   ((Win32Platform = VER_PLATFORM_WIN32_WINDOWS) and ((OSVersionInfo.dwMajorVersion > 4) or
   ((OSVersionInfo.dwMajorVersion = 4) and (OSVersionInfo.dwMinorVersion > 0)))) then
begin
  Result := false;
  ForegroundThreadID := GetWindowThreadProcessID(GetForegroundWindow,nil);
  ThisThreadID := GetWindowThreadPRocessId(AppHandle,nil);
  if AttachThreadInput(ThisThreadID, ForegroundThreadID, true) then
  begin
    BringWindowToTop(AppHandle);
    SetForegroundWindow(AppHandle);
    AttachThreadInput(ThisThreadID, ForegroundThreadID, false);
    Result := (GetForegroundWindow = AppHandle);
  end;
  if not Result then
  begin
    SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, @timeout, 0);
    SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(0), SPIF_SENDCHANGE);
    BringWindowToTop(AppHandle);
    SetForegroundWindow(AppHandle);
    SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, TObject(timeout), SPIF_SENDCHANGE);
    Result := (GetForegroundWindow = AppHandle);
    if not Result then
      begin
      ShowWindow(AppHandle,SW_HIDE);
      ShowWindow(AppHandle,SW_SHOWMINIMIZED);
      ShowWindow(AppHandle,SW_SHOWNORMAL);
      BringWindowToTop(AppHandle);
      SetForegroundWindow(AppHandle);
      end;
  end;
end else
begin
  BringWindowToTop(AppHandle);
  SetForegroundWindow(AppHandle);
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.Handle); or just  ForceForeground(Handle);

also if you use form2.show and create form2 automatically then i guess you can just call ForceForeground(Form2.Handle); when your special event occurs.

Ekim
0
 

Author Comment

by:tzigi
Comment Utility
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
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 12

Expert Comment

by:Ivanov_G
Comment Utility

   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.
0
 
LVL 33

Expert Comment

by:Slick812
Comment Utility
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(TForm1, Form1);
  Application.CreateForm(TForm2, 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(Application.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.ApplicationEvents1Message(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.Handle) then
        Application.Restore;
      Show;  // Main Form will show
      EnableMenuItem(GetSystemMenu(Application.Handle, 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(GetSystemMenu(Application.Handle, 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(GetSystemMenu(Application.Handle, 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
0
 
LVL 33

Accepted Solution

by:
Slick812 earned 500 total points
Comment Utility
sorry that last code should be -

the

 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 else inherited;  // add inherited
0
 

Author Comment

by:tzigi
Comment Utility
Slick812, you have earned your points.

Just one clarification, can you repost the fixed procedure TForm2.WMSysCommand(var Message: TWMSysCommand); ?
Thanks a lot !,
 Tzigi
0
 
LVL 33

Expert Comment

by:Slick812
Comment Utility
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
0

Featured Post

Threat Intelligence Starter Resources

Integrating threat intelligence can be challenging, and not all companies are ready. These resources can help you build awareness and prepare for defense.

Join & Write a Comment

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now