пятница, 8 февраля 2013 г.

Lazarus World. Иконка в области уведомления


Для создания примера используется операционная система Fedora 18, среда программирования Lazarus IDE 1.0.4, рабочее окружение KDE 4.9.5.

 
Рисунок 1. Область уведомления KDE
 
Если Вы используете в Linux рабочее окружение KDE, GNOME или другое, то Вы, возможно, обратили свое внимание на панель расположенную в нижней части экрана, горизонтальное расположение панели в KDE используется по-умолчанию. Как можно видеть из рисунка 1, панель (показана часть панели), в моем рабочем окружение, настроена на вертикальное расположение. На панели есть область уведомления (смотрите рисунок 1), где размещаются часы, переключатель клавиатуры, регулятор громкости и иконки приложений, позволяющие иметь быстрый доступ к основным возможностям программы. Если по иконке приложения, в области уведомления, нажать левой кнопкой мыши, то обычно открывается само приложение, в том случае, если нажать правой кнопкой мыши, то открывается всплывающие меню с функциями и параметрами приложения.
 
В данном посте мы попробуем создать приложение в IDE Lazarus, это будет приложение показывающее текущее время, приложение будет иметь иконку в области уведомления. Если приложение развернуто, то по двойному нажатию на иконку левой кнопкой мыши приложение будет свернуто. Если приложение свернуто, то двойное нажатие по иконки в области уведомления развернет его. По нажатию на иконку правой кнопкой мыши появится всплывающие меню с пунктами выхода и сворачивания / разворачивания приложения.

Компонент TTrayIcon для Lazarus позволяет создавать иконку в области уведомления. Данный компонент состоит из методов, свойств и событий, которые мы и рассмотрим ниже (Описание компонента TrayIcon можно посмотреть в Википедии на freepascal.org):
  1. Методы
  • procedure Show; — Показать иконку в области уведомления
  • procedure Hide; – Убрать иконку из области уведомления
  • function GetPosition: TPoint; - Возвращает позицию иконки из области уведомления на экране. Это функция использовалась для показа сообщения рядом с иконкой. На сегодня эта функция — заглушка, её реализация не доступна и она возвращает TPoint(0, 0);
  1. Свойства
  • property Hint; - Свойство Hint показывает не пустую строку
  • property PopUpMenu: TPopUpMenu; - Всплывающие меню появляется когда пользователь нажимает правой кнопкой мыши по иконке в области уведомления.
  1. События
  • property OnPaint: TNotifyEvent; - Используется для реализации пользовательского рисования на иконке. Используйте свойство Canvas иконки
  • property OnClick: TNotifyEvent; - Событие нажатия кнопки мышки
  • property OnDblClick: TNotifyEvent; - Событие двойного нажатия кнопки мыши
  • property OnMouseDown: TMouseEvent; - Событие, когда кнопка мыши опущена
  • property OnMouseUp: TMouseEvent; - Событие, когда кнопка мыши поднята.
  • property OnMouseMove: TMouseMoveEvent; - Событие, когда курсор мыши движется над иконкой.

Откройте IDE Lazarus. При запуске Lazarus создает новый проект с формой. Запустите инспектор объектов (Object Inspector), для этого нажмите клавишу F11, если он у вас не открыт. Сохраните проект из меню File > Save As. Чтобы проект не валялся где попала, сохраните проект в отдельном каталоге, например ~/Projecs/lazarus/ex_p1/, где ~ - домашний каталог пользователя. Присвойте имя проекту на ваше усмотрение, например ex_p1.lpi, а pas — файлу, можно присвоить имя, например ex_p1_unit1.pas. Это файл, где описан класс нашей формы.

Теперь для нашей формы мы должны указать некоторые свойства, которые задаются в инспекторе объектов (Object Inspector). Первое свойство это имя (Name) формы, поэтому имени мы будем обращаться к свойствам и методам формы из исходного кода программы. Дайте ей имя , например frmClock. В свойстве заголовка (Caption) формы напишите Clock. В свойстве BorderStyle установите значение bsSingle. Теперь на заголовке формы будет только две кнопки, кнопка закрытия формы и кнопка сворачивания формы. В свойствах задания размера формы, высоты (Height) и ширины (Width), установите значения 62 и 229, соответственно. 

Так как мы пишем часы, то нам нужна функция получения текущего времени. К счастью, модуль SysUtils, идущий вместе c Lazarus IDE, содержит функцию получения текущего времени, имя данной функции Time. В документации, по функции Time, есть пример её использования. Чтобы преобразовать время в строку, то в модуле SysUtils есть функция TimeToStr.
 
На панели компонентов Lazarus IDE выберите страницу (вкладку) System. Найдите на этой странице компонент TTimer. Компонент позволяет использовать таймер в вашем приложение, т.е. другими словами, если таймер включен (свойство Enabled) , то через установленный интервал времени (свойство Interval), будет возникать событие OnTimer. Таким образом, если функция Time модуля SysUtils вкупе с функцией TimeToStr возвращает нам строку вида 00:54:00, то установив интервал таймера в одну секунду и поместив выражение TimeToStr(Time) в обработчик событий нашего таймера, событие OnTimer, то данное выражение будет возвращать, каждую секунду, строку текущего времени: 00:54:01, 00:54:02 и т.д. Далее, нам останется, каждую секунду, присваивать данную строку текущего времени свойству Caption компонента TLable, который в свою очередь размещен на форме.
 
Переходим к реализации. Разместите на форме с именем frmClock компонент TTimer и присвойте таймеру имя (свойство Name) timerClock. Убедитесь, что свойство Interval установлено в 1000 мс, что эквивалентно одной секунде. Разместите на форме компонент TLabel и присвойте ему имя (свойство Name) lblClock. Найти его можно на странице компонентов Standard. Если дважды нажать по иконке компонента таймера с именем timerClock, то в исходном коде формы frmClock (файл с именем ex_p1_unit1.pas) появится процедура-обработчик (timerClockTimer) события OnTimer. В данном обработчике нужно свойству Caption, метке с именем lblClock, присвоить строку, которую возвращает конструкция TimeToStr(Time). Полный вид обработчика выглядит так:

procedure TfrmClock.timerClockTimer(Sender: TObject);  
begin
 lblClock.Caption := TimeToStr(Time);  
end;

Ниже на рисунке 2 показан исходный файл формы ex_p1_unit.pas, инспектор объектов, и форма с размещенными на ней компонентами lblClock и timerClock.

Рисунок 2. Редактор кода, инспектор объектов и форма в режиме редактирования
 
Далее нужно скомпилировать наш проект и запустить его. Для этого нажмите клавишу F9 или зеленый треугольник в главном окне Lazarus IDE. В результате вы должны увидеть запущенную форму с отображаемым на ней текущем временем операционной системы (рисунок 3).

 
Рисунок 3. Скомпилированный проект и запущенная форма. Во общем, это часики.

Нам осталось добавить нашему примеру возможность размещаться в области уведомления и по нажатию на иконку в области уведомления показывать всплывающие меню.

На панели компонентов выберите страницу Additional, найдите на ней компонент TTrayIcon и разместите на нашей форме с именем frmClock. Присвойте этому компоненту, в свойстве Name, имя TrayIconClock. Далее пройдемся по нескольким свойствам компонента TTrayIcon которые мы задействуем в нашем проекте. Первое свойство Visible, отвечает за отображение иконки в области уведомления, если значение данного свойства True, то иконка появится в области уведомления после запуска приложения. Если значения False, то иконки не будет видно. Что бы иконка появилась при появление нашей формы, то в обработчике события OnShow для формы frmClock необходимо прописать следующий код:

procedure TfrmClock.FormShow(Sender: TObject);
begin  
 TrayIconClock.Show;
end;

Свойство Hint (Подсказка), выводит подсказку когда вы наводите курсор мыши на иконку вашего приложения в области уведомления, присвойте данному свойству значение строки, например My Clock. Свойство Icon хранит в себя изображение иконки вашего приложения, которое будет выведено в область уведомления. Подготовьте изображением размером 128x128 пикселей, сохраните его в одном из форматов (PNG, BMP, ICO, JPG, TIF, GIF или другой, на ваш выбор) поддерживающих данным свойством. И поместите данное изображение в свойстве Icon. Мое изображение выглядит как показано на рисунке 4.

Рисунок 4. Изображение иконки в области уведомления

Теперь можно запустить наш проект и мы увидим приложение-часы с иконкой в области уведомления (Рисунок 5).

 
Рисунок 5. Часики с иконкой в области уведомления
 
Далее будем писать реакцию на нажатие мышки по иконке. В своем арсенале, компонент TTrayIcon имеет перечень событий, которые срабатывают когда мы, например, один раз или дважды нажимаем курсором мышки по иконке из области уведомления. Их можно найти в инспекторе объекта, при условии если выбран наш компонент TTrayIcon (рисунок 6). В данном случае нас интересует событие при двойном нажатие левой кнопкой мышки по иконке.

 
Рисунок 6. События компонента TTrayIcon
 
Давайте пропишем в обработчике события OnDblClick компонента TTrayIcon следующий код:

procedure TfrmClock.TrayIconClockDblClick(Sender: TObject);  
begin  
if fHide then
begin  
 frmClock.Show;  
 MenuItemHide.Caption := '&Hide';  
 fHide := False;  
end  
else  
begin
 frmClock.Hide;
 MenuItemHide.Caption := '&Show';
 fHide := True;
end;  
end;

Здесь как вы можете заметить введена глобальная булева переменная fHide, которая сообщает нам в каком состояния находится наше приложение, спрятано оно в область уведомления или нет. Если форма спрятана, то показываем ее, иначе прячем. При этом не забываем поменять название состояния формы в всплывающем меню на противоположенное и установить флаг fHide.

Выше я упомянул об всплывающем меню, которое появляется при нажатие на иконку в области уведомления правой кнопкой мыши. Давайте приступим к его реализации. На панели компонентов выберите страницу Standard, найдите на ней компонент с именем TpopupMenu и разместите его на форме. В свойстве Name инспектора объекта, присвойте ему имя PopupMenuClock. Не забудьте указать объекту с именем TrayIconClock в свойстве PopUpMenu объект с именем PopupMenuClock. Это чтобы TrayIconClock знал какое всплывающее меню показывать (рисунок 7).

 
Рисунок 7. Присоединяем PopupMenuClock к TrayIconClock

Рисунок 8. Создаем всплывающие меню

Выберите наш объект с именем PopupMenuClock в инспекторе объектов, нажмите по нему правой кнопкой мыши, откроется подменю в котором нужно нажать на пункт меню Menu Editor... Далее откроется редактор меню, в котором нам нужно добавить два пункта Hide и Exit (Рисунок 8). Данные пункты являются объектами класса TMenuItem с именами MenuItemHide и MenuItemExit, соответственно.

Чтобы добавить новые пункты меню, то необходимо в редакторе меню выбрать пустой пункт меню (показан пустым прямоугольником, на картинке не показан) правой кнопкой мыши и в выпадающем меню выбрать пункт Insert New Item (after) или Insert New Item (before) (Рисунок 9). После успешного создания закройте редактор меню.

 
Рисунок 9. Редактор меню
 
Осталось написать обработчики для наших только что созданных пунктов всплывающего меню Hide и Exit.

Обработчик нажатия на пункт меню Exit. Здесь мы закрываем форму.

procedure TfrmClock.MenuItemExitClick(Sender: TObject);  
begin  
 frmClock.Close;
end;

Обработчик нажатия на пункт меню Hide. Здесь мы прячем или показываем форму, меняя при этом названия пунктов меню Hide / Show, и устанавливая булеву переменную fHide (описание смотрите выше) в True или False.

procedure TfrmClock.MenuItemHideClick(Sender: TObject);  
begin
 if fHide then
 begin  
  frmClock.Show;  
  MenuItemHide.Caption := '&Hide';
  fHide := False;  
end  
else  
begin
 frmClock.Hide;  
 MenuItemHide.Caption := '&Show';
 fHide := True;  
end; 
end;

Напоследок покажу всю картину проекта целиком (Рисунок 10).

Рисунок 10. Результат работы приложение-часы
 
Приложение 1. Код файла проекта ex_p1.lpr
program ex_p1;

{$mode objfpc}{$H+}

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms, ex_p1_unit1
  { you can add units after this };

{$R *.res}

begin
  RequireDerivedFormResource := True;
  Application.Initialize;
  Application.CreateForm(TfrmClock, frmClock);
  Application.Run;
end.



syntax highlighted by Code2HTML, v. 0.9.1

Приложение 2. Код класса нашей формы ex_p1_unit.pas
unit ex_p1_unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics,  
  Dialogs,  StdCtrls, ExtCtrls, Menus;

type

  { TfrmClock }

  TfrmClock = class(TForm)
    lblClock: TLabel;
    MenuItemHide: TMenuItem;
    MenuItemExit: TMenuItem;
    PopupMenuClock: TPopupMenu;
    timerClock: TTimer;
    TrayIconClock: TTrayIcon;
    procedure FormShow(Sender: TObject);
    procedure MenuItemExitClick(Sender: TObject);
    procedure MenuItemHideClick(Sender: TObject);
    procedure timerClockTimer(Sender: TObject);
    procedure TrayIconClockDblClick(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  frmClock: TfrmClock;
  fHide: Boolean = False;

implementation

{ TfrmClock }

procedure TfrmClock.timerClockTimer(Sender: TObject);
begin
  lblClock.Caption := TimeToStr(Time);
end;

procedure TfrmClock.FormShow(Sender: TObject);
begin
  TrayIconClock.Show;
end;

procedure TfrmClock.MenuItemExitClick(Sender: TObject);
begin
  frmClock.Close;
end;

procedure TfrmClock.MenuItemHideClick(Sender: TObject);
begin
     if fHide then
     begin
          frmClock.Show;
          MenuItemHide.Caption := '&Hide';
          fHide := False;
     end
     else
     begin
          frmClock.Hide;
          MenuItemHide.Caption := '&Show';
          fHide := True;
     end;
end;

procedure TfrmClock.TrayIconClockDblClick(Sender: TObject);
begin
     if fHide then
     begin
          frmClock.Show;
          MenuItemHide.Caption := '&Hide';
          fHide := False;
     end
     else
     begin
          frmClock.Hide;
          MenuItemHide.Caption := '&Show';
          fHide := True;
     end;
end;

{$R *.lfm}

end
 


syntax highlighted by Code2HTML, v. 0.9.1