Секреты иконки в системном трее. Часть 1

Наверняка многие, кто начинает программировать на Delphi нередко задавались такими вопросами как:

А как можно поместить иконки приложения в системный трей Windows возле часов?
Как скрыть главную форму приложения при запуске и показывать ее по команде всплывающего меню иконки приложения в системной трее, и как затем скрыть ее обратно?
Знакомо да? Что ж, сам я тоже когда-то был начинающим программистом, и потратил уйму времени и нервов за изучение и поиска решений для всех вышеизложенных вопросов. И именно сейчас я готов изложить Вам все свои знания по части работы с иконкой приложения в системной трее.
Статью я решил разделить на две части. Что содержит каждая из них догадаться не трудно - вопросов, о решении которых я расскажу тоже две.
Итак, это часть 1: "Добавление иконки в системный трей".

В этой части мы научимся:

добавлять, изменять и удалять иконку.
отлавливать события мыши на иконке (наведение, клик, двойной клик и т.д.)
менять иконку во время работы приложения, а также текст всплывающей подсказки.
Начать статью я решил не с описания всевозможных компонентов для данной сферы программинга (которых полным полно в интернете), а с описания азов - WinAPI функций, предназначенных для работы с system tray. Хотя, "функции", как то больно громко получилось. На самом деле она всего одна:


function Shell_NotifyIcon ( dwMessage: Cardinal; lpData: PNotifyIconData ) : LongBool;  

(я привожу Вам упрощенное представление функции сделанное лично мной, т.к. если взять описание функции из WinAPI SDK - понять его будет намного труднее)
подробнее о параметрах:
dwMessage:

Параметр, а точнее команда, которая указывает этой функции что именно она должна делать. Может принимать следующие значения констант:
NIM_ADD - добавляет иконку в трей
NIM_DELETE - удаляет иконку из системного трея
NIM_MODIFY - меняет (обновляет) иконку в системном трее.
lpData:
Сей параметр есть запись, которая содержит всю информацию об добавляемой, удаляемой или изменяемой иконке. Данная запись имеет вид:

_NOTIFYICONDATAA = record
   cbSize: DWORD;
   Wnd: HWND;
   uID: UINT;
   uFlags: UINT;
   uCallbackMessage: UINT;
   hIcon: HICON;
   szTip: array [0..63] of AnsiChar;
end; 

(указатель PNotifyIconData является указателем именно на эту запись)

Давайте рассмотрим, какие именно данные содержит данная запись:
cbSize: Размер данной записи;
Wnd: Handle того окна, которое будет получать сообщения от иконки;
uID: Идентификатор иконки;
uFlags: Здесь содержатся константы, означающие, какие данные верны в записи:
NIF_ICON - hIcon содержит верную информацию.
NIF_MESSAGE - uCallbackMessage содержит верную информацию.
NIF_TIP -szTip содержит верную информацию.
(Подробнее об этом я расскажу ниже)
uCallbackMessage: Назначенный Вами идентификатор сообщения, которое будет получать приложение от иконки.
hIcon: Собственно Handle иконки (TIcon.Handle).
szTip: Текст всплывающей подсказки (не более 64 символов).
Мда, наверняка ничего не понятно, да? ..особенно новичкам. Ничего! Далее я приведу код небольшой программы, написанной лично мной. Весь код программы имеет очень богатые комментарии. С их помощью понять смысл каждого шага Вам будет нетрудно:)

Ниже привожу листинг файла main.pas (файл основной и единственной формы приложения):
Внимание!: в тексте программы прошу не путать два понятия: "иконка" - это то, что собственно находится в системно трее, и "иконка (изображение)" - это то, что содержит то само изображение иконочки.


unit main;  
  
interface  
  
uses  
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,  
  ShellApi, StdCtrls, ExtCtrls, Menus;  
  
type  
  TForm1 = class(TForm)  
    GroupBox1: TGroupBox;  
    TI_Event: TLabel;  
    GroupBox2: TGroupBox;  
    TI_DC: TLabel;  
    GroupBox3: TGroupBox;  
    Icon: TImage;  
    IconFile: TEdit;  
    Browse: TButton;  
    Exit: TButton;  
    About: TButton;  
    OpenDialog1: TOpenDialog;  
    GroupBox4: TGroupBox;  
    ToolTip: TEdit;  
    SetToolTip: TButton;  
    AboutGroupBox: TGroupBox;  
    Desk: TLabel;  
    Author: TLabel;  
    Label3: TLabel;  
    Label4: TLabel;  
    email: TLabel;  
    www: TLabel;  
    procedure FormCreate(Sender: TObject);  
    procedure FormClose(Sender: TObject; var Action: TCloseAction);  
    procedure BrowseClick(Sender: TObject);  
    procedure ExitClick(Sender: TObject);  
    procedure SetToolTipClick(Sender: TObject);  
    procedure wwwClick(Sender: TObject);  
    procedure emailClick(Sender: TObject);  
    procedure AboutClick(Sender: TObject);  
  private  
    { Private declarations }  
  public  
    { Public declarations }  
   procedure IconCallBackMessage( var Mess : TMessage ); message WM_USER + 100;  
   //Здесь мы объявлем процедуру, которая будет выполнятся каждый раз, когда  
   //на иконке будет происходит какое-либо событие (клик мышки и т.п.)  
  end;  
  
var  
  Form1: TForm1;  
  
implementation  
  
{$R *.DFM}  
  
procedure TForm1.FormCreate(Sender: TObject);  
var nid : TNotifyIconData;  
begin  
  //Добавляем иконку в трей при старте программы:  
  with nid do  //Указываем параметры иконки, для чего используем структуру  
               //TNotifyIconData.  
  begin  
    cbSize := SizeOf( TNotifyIconData ); //Размер все структуры  
    Wnd := Form1.Handle; //Здесь мы указывает Handle нашей главной формы  
                         //которая будет получать сообщения от иконки.  
    uID := 1;            //Идентификатор иконки  
    uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP; //Обозначаем то, что в  
                                                  //параметры входят:  
                                                  //Иконка, сообщение и текст  
                                                  //подсказки (хинта).  
    uCallbackMessage := WM_USER + 100;            //Здесь мы указываем, какое  
                                                  //сообщение должна  высылать  
                                                  //иконочка нашей главной форме,  
                                                  //в тот момент, когда на ней  
                                                  //(иконке)  происходят  
                                                  //какие-либо события  
    hIcon := Application.Icon.Handle;             //Указываем на Handle  
                                                  //иконки (изображения)  
                                                  //(в данной случае берем  
                                                  //иконку основной формы  
                                                  //приложения. Ниже Вы увидите  
                                                  //как можно ее изменить)  
    StrPCopy(szTip, ToolTip.Text);                //Указываем текст всплывающей  
                                                  //посдказки, который берем из  
                                                  //компонента ToolTip,  
                                                  //расположенного на главной  
                                                  //форме.  
  end;  
  Shell_NotifyIcon( NIM_ADD, @nid );  
  //Собственно добавляем иконку в трей:)  
  //Обратите внимание, что здесь мы исползуем константу  
  //NIM_ADD (добавление иконки).  
  IconFile.Text:=Application.ExeName;  
  //Выводим на главной форме пусть к файлу, который содержит  
  //иконку (изображение):)  
  Icon.Picture.Icon:=Application.Icon;  
  //Теперь выводим на главной форме изображение  
  //иконки (изображения) в увеличенном виде  
end;  
  
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);  
var nid : TNotifyIconData;  
begin  
  with nid do  
  begin  
    cbSize := SizeOf( TNotifyIconData );  
    Wnd := Form1.Handle;  
    uID := 1;  
    uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;  
    uCallbackMessage := WM_USER + 100;  
    hIcon := Application.Icon.Handle;  
    StrPCopy(szTip, ToolTip.Text);  
  end;  
  Shell_NotifyIcon( NIM_DELETE, @nid );  
  //Удаляем иконку из трея. Параметры мы вводим для того,  
  //чтобы функция точно знала, какую именно иконку надо удалять.  
  //Обратите внимание, что здесь мы исползуем константу  
  //NIM_DELETE (удаление иконки).  
end;  
  
procedure TForm1.IconCallBackMessage( var Mess : TMessage );  
var Mouse: TMouse;  
begin  
  case Mess.lParam of  
    //Здесь Вы можете обрабатывать все события, происходящие на иконке:)  
    //На главнй форме я специально расположил две метки, в которых,  
    //при возникновении какого-либо события будет писаться что именно произошло:)  
    //Но, теперь во второй части во время некоторых событий будут происходит  
    //реальные процессы.  
    WM_LBUTTONDBLCLK  : TI_DC.Caption   := 'Двойной щелчок левой кнопкой'       ;  
    WM_LBUTTONDOWN    : TI_Event.Caption:= 'Нажатие левой кнопки мыши'          ;  
    WM_LBUTTONUP      : TI_Event.Caption:= 'Отжатие левой кнопки мыши'          ;  
    WM_MBUTTONDBLCLK  : TI_DC.Caption   := 'Двойной щелчок средней кнопкой мыши';  
    WM_MBUTTONDOWN    : TI_Event.Caption:= 'Нажатие средней кнопки мыши'        ;  
    WM_MBUTTONUP      : TI_Event.Caption:= 'Отжатие средней кнопки мыши'        ;  
    WM_MOUSEMOVE      : TI_Event.Caption:= 'Перемещение мыши'                   ;  
    WM_MOUSEWHEEL     : TI_Event.Caption:= 'Вращение колесика мыши'             ;  
    WM_RBUTTONDBLCLK  : TI_DC.Caption   := 'Двойной щелчок правой кнопкой'      ;  
    WM_RBUTTONDOWN    : TI_Event.Caption:= 'Нажатие правой кнопки мыши'         ;  
    WM_RBUTTONUP      : TI_Event.Caption:= 'Отжатие правой кнопки мыши'         ;  
  end;  
end;  
  
procedure TForm1.BrowseClick(Sender: TObject);  
var I   : TIcon;  
    nid : TNotifyIconData;  
begin  
  //Здесь мы меням иконку приложения, для чего используем диалоговое окно  
  //(для выбора файла, который содержит изображение иконки)  
  //Итак, все потизоньку:  
  if OpenDialog1.Execute then //Запуск диаголового окна  
  begin  
    I:=TIcon.Create; //Создаем объект I типа TIcon  
    I.LoadFromFile(OpenDialog1.Filename); //Теперь загружаем в него изображение  
                                          //из того файла, который был выбран в  
                                          //окне диалогового окна  
    //Далее делаем все тоже самое, что и раньше, создаем структуру типа  
    //TNotifyIconData куда заносим все параметры иконки:)  
    with nid do  
    begin  
      cbSize := SizeOf( TNotifyIconData );  
      Wnd := Form1.Handle;  
      uID := 1;  
      uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;  
      uCallbackMessage := WM_USER + 100;  
      hIcon := I.Handle;  
      StrPCopy(szTip, ToolTip.Text);  
    end;  
    Shell_NotifyIcon( NIM_MODIFY , @nid );  
    //А вот здесь мы заносим изменения в иконку, которая находится в системном  
    //трее обратите внимание, что здесь мы исползуем константу NIM_MODIFY  
    //(изменение иконки).  
    Icon.Picture.Icon:=I;  
    IconFile.Text:=OpenDialog1.FileName;  
    I.Free;  
  end;  
end;  
  
procedure TForm1.ExitClick(Sender: TObject);  
begin  
  //Закрываем приложение.   
  Close;  
end;  
  
procedure TForm1.SetToolTipClick(Sender: TObject);  
var nid : TNotifyIconData;  
begin  
  //Здесь мы назначаем всплывающую посказу:)  
  //Здесь все тоже самое, что и в предыдущей процедуре.  
  //Только иконка (изображение) берется из компонента Icon,  
  //который назодится на главной форме:)  
  //А текст всплывающей посказки берем из  
  //компонента ToolTip (который расположен на главной форме)  
  with nid do  
  begin  
      cbSize := SizeOf( TNotifyIconData );  
      Wnd := Form1.Handle;  
      uID := 1;  
      uFlags := NIF_ICON or NIF_MESSAGE or NIF_TIP;  
      uCallbackMessage := WM_USER + 100;  
      hIcon := Icon.Picture.Icon.Handle;  
      StrPCopy(szTip, ToolTip.Text);  
  end;  
  Shell_NotifyIcon( NIM_MODIFY , @nid );  
  //.. и снова меням иконку:)  
end;  
  
//Далее идут процедуры, относящие работе сведений о программе  
//Тут нет ничего сложного :-)  
procedure TForm1.wwwClick(Sender: TObject);  
begin  
  ShellExecute(Application.Handle,'open','http://delphi.hostmos.ru',nil,nil,0);  
end;  
  
procedure TForm1.emailClick(Sender: TObject);  
begin  
  ShellExecute(Application.Handle,'open','mailto:srustik@rambler.ru',nil,nil,0);  
end;  
  
procedure TForm1.AboutClick(Sender: TObject);  
begin  
  if Form1.Width=250 then  
  begin  
    Form1.Width:=430;  
    About.Caption:='О Программе <<';  
  end  
  else begin  
    Form1.Width:=250;  
    About.Caption:='О Программе >>';  
  end;  
  AboutGroupBox.Visible:=not AboutGroupBox.Visible;  
end;  
  
end.  
end.  

Вот в принципе и все:) Надеюсь данная часть помогла Вам понять азы работы с системным треем:)

Автор: Рустик
Теги:
трей
Добавлено: 07 Августа 2018 07:42:27 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...