?
Solved

How to Show a Child Form while the Application is Minimized

Posted on 2004-04-23
9
Medium Priority
?
980 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 3
  • 2
  • 2
  • +2
9 Comments
 
LVL 12

Expert Comment

by:Ivanov_G
ID: 10904357
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
ID: 10904694
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
ID: 10904934
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:tzigi
ID: 10906608
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
 
LVL 12

Expert Comment

by:Ivanov_G
ID: 10907243

   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 34

Expert Comment

by:Slick812
ID: 10908483
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 34

Accepted Solution

by:
Slick812 earned 2000 total points
ID: 10908516
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
ID: 10908929
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 34

Expert Comment

by:Slick812
ID: 10913414
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

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…
In this video, Percona Solution Engineer Rick Golba discuss how (and why) you implement high availability in a database environment. To discuss how Percona Consulting can help with your design and architecture needs for your database and infrastr…
Suggested Courses
Course of the Month10 days, 12 hours left to enroll

765 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