В связи с развитием ИТ индустрии и качеством программного обеспечения в частности, хотелось бы написать статью для программистов, использующих в своём не легком деле популярную среду разработки Delphi. Речь пойдёт о работе элемента интерфейса ОС Windows
SysTray (это там где находятся часы). SysTray, как вы знаете, используют большое количество популярных программ типа WinAmp, Dr.Web, и
т.п. и т.д. А что же мешает прикрутить эту фитчу к программе разработанной нашими собственными руками
(и мозгами)? Большинство скажет: «А что тут думать то? Возьмём компонент и…», и в противовес таким мнениям у меня есть утверждение – наша программа будет весить куда меньше и работать быстрее без этого компонента. Так что забудьте о халяве.
Сразу хочу пояснить некоторые вещи. Нет такого понятия «свернуть в трей». Можно только: добавлять, удалять и менять значок в области трея. А основное окно программы прячется или минимизируется. Для работы со значками в трее нам понадобится функция Shell_NotifyIcon из модуля ShellApi (не забудь включить этот модуль после слова uses). Сначала разработаем процедуру которая будет выполнять вышеперечисленные действия со значком в SysTray’ее.

procedure TForm1.ActionIcon(n:Integer;Icon:TIcon);
Var Nim:TNotifyIconData;
begin
With Nim do //
Заполняем структуру
Nim….

Begin
cbSize:=SizeOf(Nim); //
Размер
Wnd:=Form1.Handle; //
Хендл нашего приложения(окна)
uID:=1;
uFlags:=NIF_ICON or NIF_MESSAGE or NIF_TIP;
hicon:=Icon.Handle; //
Хендл передаваемой
в процедуру иконки

uCallbackMessage:=wm_user+1;
szTip:=’Сообщение появляющееся при наведении’;
End;
Case n OF //
Действия выполняемые процедурой
1: Shell_NotifyIcon(Nim_Add,@Nim);
2: Shell_NotifyIcon(Nim_Delete,@Nim);
3: Shell_NotifyIcon(Nim_Modify,@Nim);
End;
end;

Как видим в процедуру передаётся два параметра, это
n — действие которое нужно выполнить и Icon —
иконка, которую нужно загрузить. Теперь, нам нужно заменить стандартную минимизацию приложения, на нашу — «свёртывание в трей». Как это сделать? Очень просто. При нажатии пользователем на кнопку «минимизации» всевластная Windows посылает нашему окну сообщение WM_SYSCOMMAND и структуру Msg с параметром WParam равным SC_MINIMIZE. Как только наше окно примет это сообщение оно минимизируется в нижнюю панель (TaskBar). Т.е. для того, что бы окно «свёртывалось» в наш трей мы должны перехватить это сообщение (посылаемое Windows) и сделать то, что мы хотим. Для этого объявляем в секции protected нашего объекта TForm процедуру

Procedure WindowMessage(Var Msg:TMessage); message WM_SYSCOMMAND;

После объявления процедуры нестандартная запись — message WM_SYSCOMMAND она и даёт нам перехватить сообщения о свёртывании окна. Описание же самой процедуры будет следующим

Procedure TForm1. WindowMessage (Var Msg:TMessage);
Begin
IF Msg.WParam=SC_MINIMIZE then Begin
ActionIcon (1,Application.Icon); //
Добавляем значок в трей
ShowWindow(Handle,SW_HIDE); //
Скрываем программу
ShowWindow(Application.Handle,SW_HIDE); //
Скрываем кнопку с TaskBar’а

End else inherited;

End;

Процедура, как видно, не свёртывает окно приложения, а просто прячет его функцией ShowWindow(Handle,SW_HIDE); (то о чём я говорил в начале). Итак, теперь наш обработчик ловит сообщение о минимизации и прячет нашу программу в трей. Однако ловит не всегда. Попробуем, например, выбрать из системного меню команду Minimize или нажать на кнопку окна в панели задач, и что же? Не срабатывает! Поэтому, нам нужно ещё переопределить обработчик onMinimize класса TApplication. Лучше всего это сделать при создании нашего окна, поэтому пишем в событии OnCreate

Procedure TForm1.Form1Create(Sender:TObject);
Begin
Application.onMinimize:=OnMinimizeProc;
End;

Сама же процедура выглядит так

Procedure TForm1.OnMinimizeProc(Sender:TObject);
Begin
PostMessage(Handle,WM_SYSCOMMAND,SC_MINIMIZE,0);
End;

Функция PostMessage(Handle, WM_SYSCOMMAND, SC_MINIMIZE,0); просто посылает нашему окну сообщение о минимизации, а оно в свою очередь запускает процедуру WindowMessage.
Теперь наше приложение свёртывается в SysTray. Следующая задача
— чтобы значок в трее мог реагировать на манипуляции с ним, т.е. чтобы приложение «показалось» при нажатии на значке мышкой. Строим всё по аналогии с предыдущими рассуждениями. При щелчке пользователем на иконку нашему приложению передаётся сообщение WM_USER+1 со структурой Msg, где её параметр LParam равен M_LBUTTONUP – если щелчёк был один или WM_LBUTTONDBLCLK- двойной щелчок по иконке (всё сказано для левой кнопки мыши). В секции protected пишем 

Procedure MouseClick(var Msg:TMessage); message WM_USER+1;

Сама процедура

procedure TForm1.MouseClick(var Msg:TMessage);
Var p:tpoint;
begin
GetCursorPos(p); //
Запоминаем координаты курсора мыши(см.
P/S)

Case Msg.LParam OF //
Проверяем какая кнопка была нажата
WM_LBUTTONUP,WM_LBUTTONDBLCLK: {
Действия, выполняемый по одинарному или двойному щелчку левой кнопки мыши на значке}
Begin 
ActionIcon (2,Application.Icon); //
Удаляем значок из трея
ShowWindow(Application.Handle,SW_SHOW); //
Восстанавливаем кнопку программы
ShowWindow(Handle,SW_SHOW); //
Восстанавливаем окно программы
End;
End;
end;

Процедура MouseClick перехватывает сообщение о щелчке на иконку и выполняет противоположные действия процедуре WindowMessage.

Всё на этом можно и закончить. Поставленные задачи были выполнены и без всяких там компонентов. 

З.Ы. Кстати, если вы хотите чтобы значок в трее реагировал на правое нажатие кнопки мыши и открывал менюшку, сделать нужно следующее. Киньте на форму компонент TPopUpMenu и добавьте в процедуру MouseClick
следующее

WM_RBUTTONUP:
Begin
SetForegroundWindow(Handle); //
Восстанавливаем программу в качестве переднего окна
PopupMenu1.Popup(p.X,p.Y); //
Заставляем всплыть TPopUp

PostMessage(Handle,WM_NULL,0,0);
end;

Оставить мнение

Check Also

SHA 2017. Репортаж с самого яркого хакерского ивента этого лета

Still Hacking Anyway 2017 — это фестиваль, на котором собрались четыре тысячи хакеров со в…