Главная » Delphi » Сворачивание приложения в Tray Bar вместо закрытия

0

Процесс закрытия приложения заключается в вызове метода close главной формы — неважно, закрываете ли вы его через нажатие на системную кнопку-крестик или каким-то другим путем. Для того чтобы управлять процессом закрытия, в методе предусмотрена булевская переменная canciose (по умолчанию равная True) и ряд последовательных событий, в которых эта переменная участвует. Первым возникает событие oncioseQuerry. Если в его обработчике указать Candose:=Faise, то все последующие события не произойдут — приложение не закроется. Ясно, что это нужно делать по какому-то условию, иначе приложение вообще нельзя будет закрыть. В качестве примера можно привести часто встречающийся случай закрытия программы с предварительным запросом (см. [6]; о функции MessageBox см. предыдущую главу):

procedure TForml.FormCloseQuery(Sender: TObject; var CanClose: Boolean);

var s г:string;

begin

st: = * Вы действительно хотите закрыть программу?'; if Application.MessageBox(Pchar(st),’Warning’,MB_YESNO) = IDNO then CanClose:=False else CanClose:=True; end;

Нам же нужно, чтобы вместо закрытия исполнялась та процедура, которая описана ранее — в Тгау возникала иконка, а главное окно формы исчезало. К сожалению, переменная CanClose не является глобальной, потому ей нельзя присвоить значение False заранее, так что придется изворачиваться. Мы поступим следующим образом: объявим глобальную булевскую переменную- флаг mayciose (типа boolean) и инициализируем ее значением False:

var

mayClose: boolean=False;

Чтобы сохранить все варианты на будущее, перед тем как вносить изменения, снова скопируйте проект SiideShow из папки Glava3\l в новую папку (на прилагаемом диске это папка GIava3\2, не забудьте исправить файл DSK — больше я об этом упоминать не буду) и изменить номер версии (пусть это будет l.l I). После чего удалите из текста обработчики событий onDeactivate и Oncreate (они нам здесь не понадобятся).

Обработчик события oncioseQuerry тогда будет выглядеть так:

procedure TForml.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin

if mayClose=False than begin

CanClose:=False; {не закрываем программу I mayClose:=True; {а при следующем запросе закроем) FHandle := AllocateHWnd(WndProc); {получаем дескриптор окна) HIconl:=CopyIcon(Application.Icon.Handle);

{получаем дескриптор иконки)

with noIconData do begin

cbSize:=5izeof(TNotifyiconData); {размер структуры}

Wnd:=FHandle; {дескриптор окна)

uID:=0; {единственная иконка)

UFiags:=NIF_MESSAGE or NIF_ICON or NIF_TIP;

{взводим все флаги) SzTip^’SlideShow"; {всплывающая подсказка) HIcon:=HIconl; {дескриптор иконки) uCallBackMessage:=Ico_Message;

{определяемое пользователем сообщение)

end;

Shell_NotifyIcon(NIM_ADD,SnoIconData); {создали иконку) Forml.Hide; {скрыли окно) end else {если можно закрыть, т. е. если mayClose=True) begin

DeallocateHWnd(FHandle); {убираем из памяти дескриптор окна) Shell_NotifyIcon(NIM_Delete,SnoIconData); {удаляем иконку) CanClose:=true; {можно закрывать) end; end;

Логика этой процедуры такова: сначала флаг mayciose имеет значение False, и потому при попытке закрытия будет выполнена процедура по этому условию, т. е. создастся иконка, закроется окно, а само приложение не закроется (canciose=Faise), но при следующем запросе на закрытие выполнится уже процедура ПО условию mayClose=True.

Нам теперь нужно сделать две вещи: во-первых, организовать процедуру восстановления окна, во-вторых, обеспечить возможность закрытия программы.

Самый простой путь— например, модифицировать процедуру winProc так, чтобы при щелчке левой кнопкой окно восстанавливалось, а при щелчке правой — приложение закрывалось. Но это неочевидное и потому неграмотное решение — правильный путь лежит через создание контекстного меню. В палитре Standard находим компонент PopupMenu, переносим его на форму и создаем в нем два пункта: Восстановить (название его пусть будет PopupRestorel) и Закрыть (popupClosel). Теперь переписываем процедуру winProc следующим образом: procedure TForml.WndProc(var Message: TMessage); {обработка

пользовательских сообщений/

begin

if Message.Msg = Ico_Msssage then begin

if Message.lParam=WM_LBUTTONUP then

(была отпущена левая кнопка}

begin

mayClose:=False; (теперь снова нельзя закрыть программу} Forml.Show; {восстанавливаем окно}

Application.BringToFront; (помещаем его поверх всех окон} DeallocateHWnd(FHandle);

(убираем из памяти дескриптор окна} Shell_NotifyIcon(NIM_Delete,@noIconData); (удаляем иконку) Application.ProcessMessages;

{на всякий случай обрабатываем системные сообщения}

end;

if Message. lParai№=WM_RBUTTONUP then

{была отпущена правая кнопка) Forml.PopupMenul.Popup(Screen.Width-32,Screen.Height-32);

{вызываем всплывающее меню)

end; end;

Здесь при восстановлении окна флаг mayciose опять принимает значение False, так что при новой попытке закрытия все опять повторится сначала. Всплывающее меню для простоты мы расположили на фиксированном расстоянии в 32 пиксела от нижнего и правого края экрана — примерно там, где находится наша иконка. И наконец, напишем два обработчика для пунктов Восстановить и Закрыть:

procedure TForml.PopupRestorelClick(Sender: TObject); begin

mayClose:=False; (теперь снова нельзя закрыть программу) Forml.Show; {восстанавливаем окно)

Application.BringToFront; {помешаем его поверх всех окон) DeallocateHWnd(FHandle); (убираем из памяти дескриптор окна) Shell_NotifyIcon(NIM_Delete,@noIconData); (удаляем иконку) Application.ProcessMessages;

{на всякий случай обрабатываем системные сообщения}

end;

prooedure TForml.PopupCloselClick(Sender: TObject); begin

Forml.Close; (закрываем программу – для этого все готово/ end;

Первый из них, как видите, просто дублирует то, что происходит при щелчке левой кнопкой на иконке в Tray и сделан больше "для порядка", чем для каких-то практических нужд. Теперь наша программа при попытке штатного закрытия будет сворачиваться в иконку, откуда ее можно восстановить сразу двумя путями, а закрыть ее можно будет только через контекстное меню. Попробуйте самостоятельно модифицировать программу так, чтобы при щелчке правой кнопкой (при ее нажатии) выскакивало всплывающее меню, а при ее отпускании срабатывал один из пунктов этого меню (Восстановить или Закрыть), в зависимости от того, где именно расположен курсор при отпускании — это сократит необходимое количество щелчков, но потребует некоторого усложнения программы с использованием функций определения координат мыши. Подробнее я здесь не буду на этом останавливаться — потом мы будем говорить о некоторых нюансах использования мыши и клавиатуры. Только еще одно замечание: наше всплывающее меню не оказалось истинно "всплывающим": при потере фокуса оно останется на экране и будет "торчать" там до тех пор, пока мы не щелкнем какой-либо из его пунктов. А это не очень корректно, т. к. щелкнуть на иконке можно просто по ошибке. Как сделать, чтобы оно в таком случае убиралось автоматически? Создадим обработчик события onPopup этого меню, и впишем туда одну-единственную строку:

procedure TForml.. PopupMenulPopup (Sender : TObject) ; begin

SetForegroundWindow(Formi.Handle);

(меню убирается автоматически при потере фокусаI end;

Кстати, присваивание горячих клавиш пунктам всплывающего меню в данном случае просто ничего не даст— их нажатие будет проигнорировано, управлять можно только мышью. Для того чтобы клавиши работали тоже, их нажатие нужно перехватывать — этим мы займемся позже.

Источник: Ревнч Ю. В.  Нестандартные приемы программирования на Delphi. — СПб.: БХВ-Петербург, 2005. — 560 е.: ил.

По теме:

  • Комментарии