Перед тем, как мы перейд╠м к рассмотрению конкретных функций, разрешить
посвятить несколько строк теории...
Наиболее важным свойством иконки на панели задач является то, что она обеспечивает обратную связь. Всякий раз, когда вы щ╠лкаете на иконке мышью, ваша программа получает два сообщения о нажатии кнопки и об е╠ отпускании. Если вы хоть немного знакомы с программированием в Windows, то понимаете, что для получения сообщений от панели задач вам потребуется окно. Поэтому первая ключевая идея каждая иконка на панели задач должна быть связана с каким-нибудь окном (формой в терминологии Delphi). Вторая идея заключается в том, что форма может создать на панели задач несколько иконок, поэтому нам потребуется номер иконки для того, чтобы их различать. Номера иконок мы будем выбирать сами, соблюдая единственное правило у двух разных иконок номера не совпадают. Наконец, последнее... Иконка может быть помещена на панель задач, удалена с панели задач и изменена. Эти три операции над иконкой можно выполнить при помощи единственной функции Shell_NotifyIcon. Давайте рассмотрим список е╠ параметров: uses ShellAPI; function Shell_NotifyIcon(dwMessage: DWORD; lpData: PNotifyIconData): BOOL; stdcall; Кроме этой функции, нам потребуется описание структуры данных TNotifyIconData: uses ShellAPI; TNotifyIconData = record cbSize: DWORD; Wnd: HWND; uID: UINT; uFlags: UINT; uCallbackMessage: UINT; hIcon: HICON; szTip: array [0..63] of AnsiChar; end; Для того, чтобы поместить на панель задач иконку, мы должны правильно заполнить поля записи TNotifyIconData и вызвать функцию Shell_NotifyIcon с параметром dwMessage, равным NIM_ADD: procedure TForm1.FormCreate(Sender: TObject); var NotifyIconData: TNotifyIconData; begin with NotifyIconData do begin cbSize := SizeOf(TNotifyIconData); Wnd := Handle; uID := 1; // это число мы выбираем сами uFlags := NIF_ICON or NIF_TIP; // uCallbackMessage := hIcon := Application.Icon.Handle; szTip := 'Пример иконки на панели задач'; end; Shell_NotifyIcon(NIM_ADD, @NotifyIconData); end; При создании формы на панели задач появиться иконка, такая же, как у нашей программы (поле hIcon). Если мы навед╠м мышиный курсор на эту иконку, то Windows покажет подсказку "Пример иконки на панели задач" (поле szTip). Поле uFlags определяет, какие именно параметры иконки будут определены или изменены. Оно может принимать следующие значения:
Для того, чтобы удалить иконку, мы должны вызвать функцию Shell_NotifyIcon снова, но уже с параметром NIM_DELETE. Это удобнее всего сделать при уничтожении формы: procedure TForm1.FormDestroy(Sender: TObject); var NotifyIconData: TNotifyIconData; begin with NotifyIconData do begin cbSize := SizeOf(TNotifyIconData); Wnd := Handle; uID := 1; end; Shell_NotifyIcon(NIM_DELETE, @NotifyIconData); end; Единственный вопрос, который мы ещ╠ не затронули как узнать, что пользователь щ╠лкнул левой кнопкой мыши на иконке? В этом случае Windows посылает окну, дескриптор которого переда╠тся в поле Wnd; сообщение, номер которого переда╠тся в поле uCallbackMessage. Естественно, это сообщение является пользовательским сообщением (если вы понимаете, что это означает). Если вы не знаете, что это такое ничего страшного; вы можете просто взять мой код и вставить его в свою программу. uses Windows; const WM_TASKBARICON = WM_USER + 1; type TForm1 = class(TForm) procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } procedure WMTaskBarIcon(var M: TMessage); message WM_TASKBARICON; public { Public declarations } end; implementation {$R *.DFM} procedure TForm1.WMTaskBarIcon(var M: TMessage); begin // Здесь M.WParam равно uID иконки, пославшей сообщение // M.LParam может принимать одно значения: WM_LBUTTONDOWN, // WM_LBUTTONUP, WM_MOUSEMOVE и т.д. // Я надеюсь, назначение этих сообщений очевидно... :) if (M.WParam = 1) and (M.LParam = WM_LBUTTONDOWN) then MessageBeep(-1); end; procedure TForm1.FormCreate(Sender: TObject); var NotifyIconData: TNotifyIconData; begin with NotifyIconData do begin cbSize := SizeOf(TNotifyIconData); Wnd := Handle; uID := 1; uFlags := NIF_ICON or NIF_TIP; uCallbackMessage := WM_TASKBARICON; hIcon := Application.Icon.Handle; szTip := 'Пример иконки на панели задач'; end; Shell_NotifyIcon(NIM_ADD, @NotifyIconData); end; procedure TForm1.FormDestroy(Sender: TObject); var NotifyIconData: TNotifyIconData; begin with NotifyIconData do begin cbSize := SizeOf(TNotifyIconData); Wnd := Handle; uID := 1; end; Shell_NotifyIcon(NIM_DELETE, @NotifyIconData); end; Красным цветом в привед╠нном примере показан текст, который вы должны будете добавить в свой модуль. Он позволит вашей форме принимать сообщения от иконки. Когда я готовил эту статью, я, естественно, написал небольшую программу, в которой проверил все привед╠нные здесь примеры. Во время тестирования этой программы выяснилась одна особенность функции Shell_NotifyIcon. Дело в том, что если вы измените иконку в вашей программе и попробуете поместить е╠ на панель задач, у вас ничего не выйдет иконка на панели задач останеться старая. Для того, чтобы менять на панели задач несколько своих иконок, вы должны будете использовать несколько компонентов типа TIcon. То есть, вместо var Icon: TIcon; . . . Icon.LoadFromFile('1.ico'); NotifyDataIcon.hIcon := Icon.Handle; . . . Icon.LoadFromFile('2.ico'); NotifyDataIcon.hIcon := Icon.Handle; вы должны писать var Icon1: TIcon; Icon2: TIcon; . . . Icon1.LoadFromFile('1.ico'); Icon2.LoadFromFile('2.ico'); . . . NotifyDataIcon.hIcon := Icon1.Handle; . . . NotifyDataIcon.hIcon := Icon2.Handle; Пример программы Вы можете загрузить здесь (taskbar.rar (3501)). У вас возникнут некоторые проблемы, если вы захотите показывать всплывающее (pop-up) меню при щелчке на вашей иконке. В ч╠м они заключаются? Для того, чтобы спрятать всплывающее меню, нужно щ╠лкнуть где-нибудь вне его. Однако, если вы попробуете вызвать меню в ответ на сообщение WM_RBUTTONUP, выяснится, что эта техника не работает нужно либо выбрать один из пунктов меню, либо щ╠лкать мышью на форме, которой это меню принадлежит (а она может быть и невидимой). Спрятав меню, вы обнаружите, что при следующем его вызове оно появляется, и тут же исчезает (это происходит только один раз). Как быть? Для решения первой проблемы вам необходимо вызывать функцию SetForegroundWindow перед вызовом меню: SetForegroundWindow(Form1.Handle); Для решения второй проблемы сразу после вызова меню необходимо активизировать текущую задачу. Это можно сделать, послав пустое сообещение нашему окну: Form1.Perform(WM_NULL, 0, 0); |