RussianDelphiProgrammingAlliance

Главная | О проекте | Новости | Статьи | Проекты | Исходники | Файлы | ЧаВо | Ссылки

Как поместить иконку на панель задач - by Mark Shevchenko

Перед тем, как мы перейд╠м к рассмотрению конкретных функций, разрешить посвятить несколько строк теории...

Наиболее важным свойством иконки на панели задач является то, что она обеспечивает обратную связь. Всякий раз, когда вы щ╠лкаете на иконке мышью, ваша программа получает два сообщения — о нажатии кнопки и об е╠ отпускании. Если вы хоть немного знакомы с программированием в 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 определяет, какие именно параметры иконки будут определены или изменены. Оно может принимать следующие значения:
NIF_MESSAGE Можно добавить или изменить обработчик сообщений. В случае использования этого флага, вы должны определить поле uCallbackMessage (подробности см. ниже).
NIF_ICON Можно добавить или изменить иконку. В случае исользования этого флага, вы должны определить поле hIcon.
NIF_TIP Можно добавить или изменить надпись (подсказку). В случае использования этого флага, вы должны определить поле szTip.
Для того, чтобы изменить какой-нибудь параметр иконки, вы можете вызвать функцию Shell_NotifyIcon с параметром dwMessage, равным NIM_MODIFY. Пользуясь полем 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);

Исходный документ находится на Mark Shevchenko Homepage

Последнее обновление - 30 мая 1999

Чужая реклама: