15

I am a Delphi learner. I am looking for solutions so that Delphi MainForm should be minimized to the System Tray instead of Taskbar. On Right Click on the System Tray Icon there should be some menus like "Restore" and "About" and "Help" etc. System Tray Icons will be loaded from Imagelis1 and it will animate. On Clicking on "Restore" the MainForm will be restored, on clicking on "About" "Form2" will be restored and on clicking on "Help" "Foprm3" will be restored. I have found so many solutions on internet like :

Solution 01

Solution 02

but every solutions have some drawbacks. Some can be done once ony. Some have blurred icon in Windows7. Someone may tell that there is no one to write codes for me and I have to show my codes. Plaese forgive me for this regards. Please give me concrete solution sot that it can be implemented universely without version dependency of windows. It will help every one. Please help me.

Community
  • 1
  • 1
Rubi Halder
  • 583
  • 3
  • 12
  • 24
  • 2
    Use the TrayIcon component provided by Delphi. Blurred icon means that the icon associated with your tray icon is not the same size as the system tray icon size (thus, Windows has to resize it), so you need to provide your icon in multiple sizes including the one that match wit system tray icon size. – Jay Aug 06 '12 at 00:03
  • 1
    Use `GetSystemMetrics(SM_CXSMICON)` to work out the required size of the icon. If you haven't got one the right size, then create a 32bpp bitmap of the right size, fill it with transparent pixels, and then blt into the middle of this bitmap, the nearest icon small than the right size. Then convert the bitmap to an icon and you are golden. For font scaling different from 100% you can get a variety of values for `SM_CXSMICON` metric. – David Heffernan Aug 06 '12 at 18:46
  • I am a learner I don't know how to use "GetSystemMetrics(SM_CXSMICON)". Please give one complete solution. If I set Form Icon, it is get blurred in Win7 and in "Alt+Tab". Please help me. – Rubi Halder Aug 07 '12 at 19:43
  • 1
    @Rubi: No. How to use `GetSystemMetrics(SM_CXSMICON)` is a separate question, and should be posted as one. Your question here is how to minimize your Delphi application to the System Tray, and you can't change it now to add something else. If you have a new question, post it as a new question. This is not a "hit the moving target" site, or a "please write me a complete program" site. – Ken White Aug 07 '12 at 21:41
  • @RubiHalder In addition to Ken Whites explanation of what this site is not, it is a "thank your peers by accepting the answer that solved your issue" site. ;-) – Sherlock70 Sep 18 '19 at 10:25

4 Answers4

26

This should get you going. Drop a TTrayIcon and a TApplicationEvents on your form. THe following code is from the TTrayIcon - Delphi Example from the docwiki. Use the IDE main menu, and choose Project->View Source, and the line that reads Application.ShowMainFormOnTaskbar := True; to `Application.ShowMainFormOnTaskbar := False;' to keep the application's button from appearing on the Windows Taskbar.

This example uses a tray icon and an application events component on a form. When the application runs, it loads the tray icon, the icons displayed when it is animated, and it also sets up a hint balloon. When you minimize the window, the form is hidden, a hint balloon shows up, and the tray icon is displayed and animated. Double-clicking the system tray icon restores the window.

// Add this to the `TApplicationEvents.OnMinimize` event handler
procedure TForm1.ApplicationEvents1Minimize(Sender: TObject);
begin
  { Hide the window and set its state variable to wsMinimized. }
  Hide();
  WindowState := wsMinimized;

  { Show the animated tray icon and also a hint balloon. }
  TrayIcon1.Visible := True;
  TrayIcon1.Animate := True;
  TrayIcon1.ShowBalloonHint;
end;

// Add this to the `TForm.OnCreate` event handler
procedure TForm1.FormCreate(Sender: TObject);
var
  MyIcon : TIcon;
begin
  { Load the tray icons. }
  TrayIcon1.Icons := TImageList.Create(Self);
  MyIcon := TIcon.Create;
  MyIcon.LoadFromFile('icons/earth1.ico');
  TrayIcon1.Icon.Assign(MyIcon);
  TrayIcon1.Icons.AddIcon(MyIcon);

  MyIcon.LoadFromFile('icons/earth2.ico');
  TrayIcon1.Icons.AddIcon(MyIcon);
  MyIcon.LoadFromFile('icons/earth3.ico');
  TrayIcon1.Icons.AddIcon(MyIcon);
  MyIcon.LoadFromFile('icons/earth4.ico');
  TrayIcon1.Icons.AddIcon(MyIcon);

  { Set up a hint message and the animation interval. }
  TrayIcon1.Hint := 'Hello World!';
  TrayIcon1.AnimateInterval := 200;

  { Set up a hint balloon. }
  TrayIcon1.BalloonTitle := 'Restoring the window.';
  TrayIcon1.BalloonHint :=
    'Double click the system tray icon to restore the window.';
  TrayIcon1.BalloonFlags := bfInfo;
end;

// Add this to the `TTrayIcon.OnDoubleClick` event handler
procedure TForm1.TrayIcon1DblClick(Sender: TObject);
begin
  { Hide the tray icon and show the window,
  setting its state property to wsNormal. }
  TrayIcon1.Visible := False;
  Show();
  WindowState := wsNormal;
  Application.BringToFront();
end;

For the menu you get on right-click, add a TPopupMenu to your form, add the items you want on it, write the event handlers for those items as usual, and then assign the PopupMenu to the TrayIcon.PopupMenu property.

The "blurred icons" are caused by you not using the proper icon sizes and Windows being forced to scale (stretch) them. Use an icon editor to create multiple size images for each icon (there can be multiple sizes in one icon file).

Ken White
  • 123,280
  • 14
  • 225
  • 444
  • Thanks a lot. Your solution is working fine with one small problem for me. In my project, I am using "Timers" for "FormMinimizing" "FormShowing" "FormHiding" and "FormRestoring". You can find my project in the following link. [**My Project**](http://stackoverflow.com/questions/11699277/delphi-form-switching-using-timer/11705857#11705857) After minimizing the Form, it goes to "SystemTray" but also available in "TaskBar". So ihave tried the solution found in [**Solution**](http://stackoverflow.com/questions/681621/hide-the-main-form-in-a-delphi-2009-application) then the form is invissible. – Rubi Halder Aug 07 '12 at 19:54
  • 1
    See my edit in the first paragraph about `Application.ShowMainFormOnTaskbar`. :-) – Ken White Aug 07 '12 at 20:56
  • 1
    It works great, but only once. After I click the tray icon it brings the form but the minimize button in the title bar of my program is no longer working, so I cannot minimize it again. – Tom Feb 21 '15 at 12:28
  • In Delphi Xe3 the Application.ShowMainFormOnTaskbar is named Application.MainFormOnTaskBar and it has to stay TRUE (the default value). Otherwise it doesn't work properly, as I mentioned above. – Tom Feb 21 '15 at 12:55
  • Using your code, this works fine for first time. But if I do the whole process again, "restore, minimize, etc.", the trayicon disappears, and the application remains minimized. – Linces Marques Mar 20 '19 at 16:53
  • 1
    In Delphi 10.4.1 using Application.Restore; resolves the problem of the form refusing to minimise a second time – Maya Mar 31 '21 at 10:55
10

I drop a TrayIcon onto myForm, then i add this simple code:

type
  TmyForm = class(TForm)
    ...
    TrayIcon: TTrayIcon;
    procedure FormCreate(Sender: TObject);
    ...
    procedure TrayIconClick(Sender: TObject);
    ...
  private
    { Private declarations }
    procedure OnMinimize(Sender:TObject);
  public
    { Public declarations }
  end;

procedure TmyForm.FormCreate(Sender: TObject);
begin // When form is created
     Application.OnMinimize:=OnMinimize; // Set the event handler for application minimize
end;

procedure TmyForm.OnMinimize(Sender:TObject);
begin // When application is minimized by user and/or by code
     Hide; // This is to hide it from taskbar
end;

procedure TmyForm.TrayIconClick(Sender: TObject);
begin // When clicking on TrayIcon
     if Visible
     then begin // Application is visible, so minimize it to TrayIcon
               Application.Minimize; // This is to minimize the whole application
          end
     else begin // Application is not visible, so show it
               Show; // This is to show it from taskbar
               Application.Restore; // This is to restore the whole application
          end;
end;

This creates a TrayIcon allways visible, and when you click on it:

  • If the application is Visible, it will be Hidden form taskbar and from screen
  • If the application is Hidden, it will be Shown form taskbar and from screen

In other words, clicking on TrayIcon the application will change its visibility; just as minimizing it to TrayIcon bar.

anonymous
  • 101
  • 1
  • 2
  • 1
    This is nice, but it doesn't take care of 2 things: when clicking on the tray icon, app is not focused. It stays minimized. And when clicking "X" the app closes instead of being minimized to tray. Any solution for these 2 issues? – bashan Nov 14 '15 at 09:28
3

...And in Delphi 6, where no TTrayIcon exists, you can use this simple code:

unit MainUnit;

interface

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

const WM_ICONTRAY = WM_USER+1;

type
  TForm1 = class(TForm)
    PopupMenu1: TPopupMenu;
    ShowForm1: TMenuItem;
    HideForm1: TMenuItem;
    Exit1: TMenuItem;
    procedure TrayMessage(var Msg: TMessage); message WM_ICONTRAY;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ShowForm1Click(Sender: TObject);
    procedure HideForm1Click(Sender: TObject);
    procedure Exit1Click(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
   TrayIconData: TNotifyIconData;
  end;

var
  Form1: TForm1;
  MustExit:boolean;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  MustExit:=false;
  TrayIconData.cbSize:=SizeOf(TrayIconData);
  TrayIconData.Wnd:=Handle;
  TrayIconData.uID:=0;
  TrayIconData.uFlags:=NIF_MESSAGE + NIF_ICON + NIF_TIP;
  TrayIconData.uCallbackMessage:=WM_ICONTRAY;
  TrayIconData.hIcon:=Application.Icon.Handle;
  StrPCopy(TrayIconData.szTip,Application.Title);
  Shell_NotifyIcon(NIM_ADD, @TrayIconData);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Shell_NotifyIcon(NIM_DELETE, @TrayIconData);
end;

procedure TForm1.TrayMessage(var Msg: TMessage);
var p:TPoint;
begin
  case Msg.lParam of
    WM_LBUTTONDOWN: begin
                     Form1.Show;
                     Application.Restore;
                    end;
    WM_RBUTTONDOWN: begin
                     GetCursorPos(p);
                     PopUpMenu1.Popup(p.x,p.y);
                    end;
  end;
end;

// Popup "Form Show" menu item OnClick 
procedure TForm1.ShowForm1Click(Sender: TObject);
begin
 Form1.Show;
end;

// Popup "Form Hide" menu item OnClick    
procedure TForm1.HideForm1Click(Sender: TObject);
begin
 Form1.Hide;
end;

// Popup "Exit" menu item OnClick
procedure TForm1.Exit1Click(Sender: TObject);
begin
 MustExit:=true;
 Close;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 if MustExit then exit;
 Form1.Hide;
 Action:=caNone;
end;

end.
Marus Gradinaru
  • 2,824
  • 1
  • 26
  • 55
1

I have implemented the following codes. Here everything is fine except one. After minimizing the Form, it goes to "SystemTray" but also available in "TaskBar. For my application, the "AlphaBlend" property of "Form001" is true and "AlphaBlendValue" is "0".

unit KoushikHalder001;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls, Vcl.Imaging.pngimage,
  Vcl.AppEvnts, Vcl.ImgList, Vcl.Menus;

type
  TForm001 = class(TForm)
    Edit001: TEdit;
    Background: TImage;
    BitBtn001: TBitBtn;
    BitBtn002: TBitBtn;
    FadeInTimer: TTimer;
    FadeOutTimer: TTimer;
    FormMinimizeTimer: TTimer;
    FormRestoreTimer: TTimer;
    TrayIcon: TTrayIcon;
    PopupMenu: TPopupMenu;
    ImageList: TImageList;
    ApplicationEvents: TApplicationEvents;
    Form001Close: TMenuItem;
    Form001Hide: TMenuItem;
    Form001Show: TMenuItem;
    Form002Close: TMenuItem;
    Form002Hide: TMenuItem;
    Form002Show: TMenuItem;
    N01: TMenuItem;
    N02: TMenuItem;
    N03: TMenuItem;
    N04: TMenuItem;
    N05: TMenuItem;
    N06: TMenuItem;
    N07: TMenuItem;
    N08: TMenuItem;
    N09: TMenuItem;
    N10: TMenuItem;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormCreate(Sender: TObject);
    procedure FormHide(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure BitBtn001Click(Sender: TObject);
    procedure BitBtn002Click(Sender: TObject);
    procedure FadeInTimerTimer(Sender: TObject);
    procedure FadeOutTimerTimer(Sender: TObject);
    procedure FormMinimizeTimerTimer(Sender: TObject);
    procedure FormRestoreTimerTimer(Sender: TObject);
    procedure ApplicationEventsMinimize(Sender: TObject);
    procedure TrayIconDblClick(Sender: TObject);
    procedure Form001CloseClick(Sender: TObject);
    procedure Form001HideClick(Sender: TObject);
    procedure Form001ShowClick(Sender: TObject);
    procedure Form002CloseClick(Sender: TObject);
    procedure Form002HideClick(Sender: TObject);
    procedure Form002ShowClick(Sender: TObject);
  private
    { Private declarations }
    CrossButtonClick: Boolean;
    procedure WMNCHitTest(var Msg: TWMNCHitTest) ; message WM_NCHitTest;
    procedure WMSysCommand(var Msg: TWMSysCommand) ; message WM_SysCommand;
  public
    { Public declarations }
  end;

var
  Form001: TForm001;

implementation

{$R *.dfm}

uses KoushikHalder002;


procedure TForm001.WMNCHitTest(var Msg: TWMNCHitTest);
begin
  inherited;
  if ControlAtPos(ScreenToClient(Msg.Pos), True, True, True)= nil
    then
      begin
        if Msg.Result=htClient then Msg.Result := htCaption;
      end;
end;

procedure TForm001.WMSysCommand(var Msg: TWMSysCommand);
begin
  case Msg.CmdType of
    SC_MINIMIZE:
      begin
        if Form001.AlphaBlendValue > 0 then
          begin
            Form001.FormMinimizeTimer.Enabled := true;
            Exit;
          end;
      end;
    SC_RESTORE:
      begin
        if Form001.AlphaBlendValue < 220 then
          begin
            Form001.FormRestoreTimer.Enabled := True;
          end;
      end;
  end;
  inherited;
end;

procedure TForm001.ApplicationEventsMinimize(Sender: TObject);
begin
  Form001.FormMinimizeTimer.Enabled := true;
  TrayIcon.Visible := True;
  TrayIcon.Animate := True;
  TrayIcon.ShowBalloonHint;
end;

procedure TForm001.BitBtn001Click(Sender: TObject);
begin
  if Form002.WindowState = wsMinimized then
    begin
      Form002.Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
    end
    else
    Form002.show;
end;

procedure TForm001.BitBtn002Click(Sender: TObject);
begin
  Form002.FadeOutTimer.Enabled := true;
  Form001.FadeOutTimer.Enabled := true;
end;

procedure TForm001.Form001CloseClick(Sender: TObject);
begin
  Form002.FadeOutTimer.Enabled := true;
  Form001.FadeOutTimer.Enabled := true;
end;

procedure TForm001.Form001HideClick(Sender: TObject);
begin
Form001.FormMinimizeTimer.Enabled := true;
end;

procedure TForm001.Form001ShowClick(Sender: TObject);
begin
  if Form001.WindowState = wsMinimized then
    begin
      Form001.Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
    end
    else
    Form001.show;
end;

procedure TForm001.Form002CloseClick(Sender: TObject);
begin
Form002.FadeOutTimer.Enabled := true;
end;

procedure TForm001.Form002HideClick(Sender: TObject);
begin
Form002.FormMinimizeTimer.Enabled := true;
end;

procedure TForm001.Form002ShowClick(Sender: TObject);
begin
  if Form002.WindowState = wsMinimized then
    begin
      Form002.Perform(WM_SYSCOMMAND, SC_RESTORE, 0);
    end
    else
    Form002.show;
end;

procedure TForm001.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Form001.FadeOutTimer.Enabled := true;
end;

procedure TForm001.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if CrossButtonClick = true
    then
      begin
        CanClose := true;
        Exit;
      end;
  CanClose := false;
  Form001.FadeOutTimer.Enabled := true;
end;

procedure TForm001.FormCreate(Sender: TObject);
begin
  Form001.FadeInTimer.Enabled := true;
end;

procedure TForm001.FormHide(Sender: TObject);
begin
  Form001.FadeOutTimer.Enabled := true;
end;

procedure TForm001.FormShow(Sender: TObject);
begin
  Form001.FadeInTimer.Enabled := true;
end;
procedure TForm001.TrayIconDblClick(Sender: TObject);
begin
  Form001.FormRestoreTimer.Enabled := true;
  TrayIcon.Visible := False;
  WindowState := wsNormal;
  Application.BringToFront();
end;

procedure TForm001.FadeInTimerTimer(Sender: TObject);
begin
  if Form001.AlphaBlendValue >= 220
    then
      begin
        Form001.FadeInTimer.Enabled := false;
      end
    else
      begin
        Form001.AlphaBlendValue := Form001.AlphaBlendValue + 10;
        CrossButtonClick := false;
      end;
end;

procedure TForm001.FadeOutTimerTimer(Sender: TObject);
begin
  if Form001.AlphaBlendValue <= 0
    then
      begin
        Form001.FadeOutTimer.Enabled := false;
        CrossButtonClick := true;
        Self.Close;
      end
    else
      begin
        Form001.AlphaBlendValue := Form001.AlphaBlendValue - 10;
        CrossButtonClick := true;
      end;
end;

procedure TForm001.FormMinimizeTimerTimer(Sender: TObject);
begin
  if Form001.AlphaBlendValue > 0 then
    begin
      Form001.AlphaBlendValue := Form001.AlphaBlendValue - 10;
    end
  else
    begin
      Form001.FormMinimizeTimer.Enabled := false;
      Perform(WM_SYSCOMMAND, SC_MINIMIZE, 0);
    end;
end;

procedure TForm001.FormRestoreTimerTimer(Sender: TObject);
begin
  if Form001.AlphaBlendValue < 220 then
    begin
      Form001.AlphaBlendValue := Form001.AlphaBlendValue + 10;
    end
  else
    begin
      Form001.FormRestoreTimer.Enabled := false;
    end;
end;

end.

If I do the following

  Application.MainFormOnTaskbar := false;

the form is totally invissible. I think there should be one bug. But I am unable to find it.

Rubi Halder
  • 583
  • 3
  • 12
  • 24