Delphirus - прграммирование на delphi
   Все о delphi Delphirus - прграммирование на delphi
blocks.gif
Навигация
 

Главная
Статьи
Базы данных
Графика
Защита
Интернет
Система
Тексты
Мультимедиа
Файлы
Формы и окна
Другое
Советы
Базы данных
Графика
Интернет
Мультимедиа
Система
Тексты
Файлы
Файлы
Исходники
Компоненты
Инфо
Поиск по сайту
Обратная связь
Самое популярное
Аккаунт
Карта сайта

 
story.gif
Секреты иконки в системной трее
 
Работа с Windows и железом     Наверняка многие, кто начинает программировать на Delphi нередко задавались такими вопросами как:

1. А как можно поместить иконки приложения в системный трей Windows возле часов?
2. Как скрыть главную форму приложения при запуске и показывать ее по команде всплывающего меню иконки приложения в системной трее, и как затем скрыть ее обратно?

    Знакомо да? Что ж, сам я тоже когда-то был начинающим программистом, и потратил уйму времени и нервов за изучение и поиска решений для всех вышеизложенных вопросов. И именно сейчас я готов изложить Вам все свои знания по части работы с иконкой приложения в системной трее.

    Статью я решил разделить на две части. Что содержит каждая из них догадаться не трудно - вопросов, о решении которых я расскажу тоже две. 

Итак, это часть 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.

 Итак, это вторая часть моей небольшой "эпопеи", посвященное иконке в системной трее.

Сегодня мы рассмотрим и научимся решать следующие вопросы:
1. Как добавить всплывающее меню к иконке?
2. Как скрывать главную форму приложения при запуске, и показываеть его по команде всплывающего меню.

Для изучения данных вопросов, мы воспользуемся все тем же примером, который использовали в первой части, и немного модернизируем его.
Откройте в Delphi исходник от первой части статьи и внесите в него следующие изменения:
1. Найдите на форме кнопку с именем "Exit". Теперь, измените ее свойство "Caption" на "Скрыть", а свойство "Name" на "BHide";
2. Добавьте на форму компонент PupopMenu и измените его свойство "Name" на "PopupMenu".
3. Теперь два раза щелкните на нем, чтобы открылся редактор меню, и создайте точно такое меню, какое показано на рисунке:



Пункту "О программе" дайте имя "PAbout", пункту "Настройки" дайте имя "PSettings", пункту "Выход" имя "PExit". У пункта "Настройки" свойство "Default" установите в "True" (этим мы делаем данный пункт меню основным, т.е. данное действие будет выполняться при двойном нажатии левой кнопки мыши на иконке приложения в системном трее. Как это сделать Вы узнаете чуть ниже). После чего закройте редактор меню.

Модернизация программы закончена. Ваша главная форма должна выглядеть примерно так:


Теперь, давайте приступим к решению вопросов, заданных в начале статьи.

Начнем мы с того, что научимся скрывать главную форму при запуске приложения. Для этого вам необходимо зайти в пункт меню самой Delphi: Project -> View Source (Проект -> Просм. источник). После чего Вашим глазам откроется содержание файла tray.dpr. Текста там немного, так что ничего страшного в этом файле нет :) Теперь, найдите там строчку
    Application.CreateForm(TForm1, Form1);
которая создает главную форму приложения, и, сразу после нее, на следующей строке напишите:  
        Application.ShowMainForm:=False;
Вот и все! Этой строкой вы запретили показ главной формы приложения при запуске. Чтобы проверить, сохраните все изменения, и запустите программу. Теперь, при запуске, Вы увидите только иконку в системном трее. Да, кстати, закрыть программу теперь возможно только в Delphi при помощи меню Run -> Program Reset, или при помощи горячих клавиш Ctrl-F2. Но это только временно, ниже мы решим эту проблему.

Далее, давайте напишем нужные коды в обработчиках событий нажатия кнопки мыши в каждом из пунктов меню:

Пункт "О программе":
procedure TForm1.PAboutClick(Sender: TObject);
begin
  //Показываем главную форму в раскрытой областью "О программе"
  AboutClick(Form1); //Выполняем процедуру нажатия на кнопку "О программе"
  Form1.Show;        //И, именно вот такой строчкой, мы показываем
                     //главную форму приложения.
  Form1.Activate;    //..и активируем ее :)
end;


Пункт "Настройки":
procedure TForm1.PSettingsClick(Sender: TObject);
begin
  //Описание сморите выше:)
  Form1.Show;
  Form1.Activate;
end;


Пункт "Выход":
procedure TForm1.PExitClick(Sender: TObject);
begin
  Close; //обыкновенный выход из программы.
end;


По моему комментарии излишне:) Надеюсь Вам понятно, что будет происходить во время этих событий.

А сейчас мы сделаем самое главное и самое интересное: заставим наше меню "всплывать" на иконке во время нажатия правой кнопки мыши, а нашу главную форму "показываться" при двойной нажатии левой кнопки мыши.

В исходном коде программы найдите процедуру IconCallBackMessage и модернизируйте ее так, чтобы она выглядела так, как показано ниже:

procedure TForm1.IconCallBackMessage( var Mess : TMessage );
var Mouse: TMouse;
begin
  case Mess.lParam of
    //Здесь Вы можете обрабатывать все события, происходящие на иконке:)
    //На главной форме я специально расположил две метки, в которых,
    //при возникновении какого-либо события будет писаться что именно произошло:)
    //Но, теперь во второй части во время некоторых событий будут происходит
    //реальные процессы.
    WM_LBUTTONDBLCLK  :  //Обрабатываем двойной щелчок левой кнопки мыши.
    begin
      PSettingsClick(Form1); //Выполняем пункт меню "Настройки".
    end;
    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      : //Обрабатываем нажатие правой кнопкой мыши.
    begin
      PopupMenu.Popup(Mouse.CursorPos.x, Mouse.CursorPos.y);
      //заставляем "всплыть" наше меню:)
    end;
  end;
end;


С первым событием двойного нажатия левой кнопки мыши наверняка все понятно - мы выполняем вызываем обработчик события нажатия кнопки мыши на пункте меню "Настройки".
Но, с нажатием правой кнопки мыши наверное потруднее да? Чтож, все по порядку:
В самом начале процедуры мы объявляем объект Mouse типа TMouse. Для того, чтобы позднее при помощи него узнать координаты мыши на экране.
Далее мы пишем следующую строчку:
      PopupMenu.Popup(Mouse.CursorPos.x, Mouse.CursorPos.y);
Смысл ее простой. Метод Popup используется для показа меню в заданной точке экрана. Именно здесь нам пригодился объект Mouse, при помощи свойств которого, мы узнаем координаты мыши на экране, во время нажатия правой кнопки мыши.
Но, в "всплывании" меню есть еще одни нюанс. Если сейчас все оставить все как есть, оно будет "зависать" при потери фокуса - т.е. просто не будет исчезать. Для устранения данного бага в обработчике события OnPopup нашего меню впишите нижеследующее:
      SetForegroundWindow(Form1.Handle);
Этим мы указываем, что активным является главная форма нашего приложения (даже если он невидима). И, при переключении между приложения оно теряет свою активность, и, соответственно, всплывающее меню исчезает из виду, т.к. оно является дочерним объектом, по отношению к форме.

Вот и в принципе и все:) ...ах, да.. совсем забыл. В самом начале мы изменили надпись на бывшей кнопке закрытия приложения на "Скрыть", т.е. теперь при ее нажатии необходимо, чтобы главная форма приложения "пряталась". Чтож, делается это просто, в обработчик события нажатия данной кнопки впишите одну единственную строку:
             Form1.Hide;
А вот теперь все! Надеюсь, по мере чтения статей этой серии Вам становится все легче и легче понять азы работы с иконкой приложения в системной трее:)



Примечание:

Рустик

Источник www.delphi.hostmos.ru

 
Разместил 06/02/2004 от rolcom ( Прочитано: )

  blocks.gif
Связанные ссылки
 

· Больше про Работа с Windows и железом
· Новость от rolcom


Самая читаемая статья: Работа с Windows и железом:
Запуск приложений из Delphi

 
blocks.gif
Рейтинг статьи
 

Средняя оценка: 4.66
Ответов: 15


Пожалуйста, проголосуйте за эту статью:

Отлично
Очень хорошо
Хорошо
Нормально
Плохо


 
blocks.gif
опции
 


 Напечатать текущую страницу  Напечатать текущую страницу

 Отправить статью другу  Отправить статью другу

 
 

Page generation 0.201 seconds