Archive for Lipiec, 2010

SystemTrayIcon i DoubleClick w Adobe Air

Niedawno rozpocząłem pracę nad aplikacją w adobe air. Jedną z niewielkich funkcjonalności była minimalizacja aplikacji do postaci ikonki w tray-u, oraz przywrócenie jej okna po dwukrotnym kliknięciu. Sam proces wczytania oraz minimalizacji nie stanowił problemu, ale ponowne pokazanie okna po dwukrotnym kliknięciu w ikonę niestety sprawiło mi nieco trudności.

Załadowana ikona w tray-u reprezentowana jest przez klasę SystemTrayIcon, która udostępnia szereg zdarzeń, niestety wśród nich brakuje obsługi podwójnego kliknięcia. Do opisywanej sytuacji pasuję przysłowie "Jak się nie ma co się lubi, to się lubi co się ma"
- innymi słowy postanowiłem wykorzystać to co mam dostępne czyli pojedyncze kliknięcie. ;)

Klasa zdarzenia "DoubleClick" dla mojej ikonki:

public class ExtendedSystemTrayIconEvent extends ScreenMouseEvent
{
	 public static const DOUBLE_CLICK:String = "doubleClick";

	 public function ExtendedSystemTrayIconEvent(type:String, bubbles:Boolean=false,
						   cancelable:Boolean=false, screenX:Number=undefined,
						   screenY:Number=undefined, ctrlKey:Boolean=false,
					    altKey:Boolean=false, shiftKey:Boolean=false,
						   buttonDown:Boolean=false, commandKey:Boolean=false,
						   controlKey:Boolean=false)
	 {
		   super(type, bubbles, cancelable, screenX, screenY,
		   ctrlKey, altKey, shiftKey, buttonDown, commandKey, controlKey);
	 }
}

Klasa dostarczająca obsługę zdarzenia:

[Event(name="doubleClick", type="ExtendedSystemTrayIconEvent"]
/**
*SystemTrayIcon DoubleClick
*This class provide double click on tray icon
*
* @author Piotr Zarzycki
*
*/
public class SystemTrayIconWraper extends EventDispatcher
{
   private var _systemTrayIcon:SystemTrayIcon;
   private var _clickCounter:int = 0;
   private var _timer:Timer;

   public function SystemTrayIconWraper(systemTrayIcon:SystemTrayIcon)
   {
		   _systemTrayIcon = systemTrayIcon;
		   _timer = new Timer(1000, 1);
		   _timer.addEventListener(TimerEvent.TIMER_COMPLETE,
                            onTimeComplete);

		   _systemTrayIcon.addEventListener(ScreenMouseEvent.CLICK,
                            onClickTrayIcon);
   }

   public function onClickTrayIcon(event:ScreenMouseEvent):void
   {
		   if (!_timer.running)
		   {
			   _timer.start();
		   }
		   _clickCounter++;
		   if (_clickCounter > 1)
		   {
			      _systemTrayIcon.dispatchEvent(
              new ExtendedSystemTrayIconEvent("doubleClick",
                     event.bubbles, event.cancelable, event.screenX,
                     event.screenY, event.ctrlKey, event.altKey,
                     event.shiftKey, event.buttonDown, event.commandKey,
                     event.controlKey));

			      _clickCounter = 0;
		   }
   }

   override public function addEventListener(type:String, listener:Function,
                                   useCapture:Boolean=false, priority:int=0,
                                   useWeakReference:Boolean=false):void
   {
		      _systemTrayIcon.addEventListener(type, listener, useCapture, priority,
                                          useWeakReference);
   }

   private function onTimeComplete(event:TimerEvent):void
   {
		   _clickCounter = 0;
		   _timer.reset();
   }
}

Klasa "SystemTrayIconWraper" dziedziczy po klasie "EventDispatcher", obsługuję zdarzenie "CLICK" dla obiektu SystemTrayIcon dostarczonego w jej konstruktorze oraz inicjalizuję klasę "Timer" wartością 1 sekundy. Dodatkowo w jej wnętrzu tworzę zmienną przechowującą ilość kliknięć na ikonkę tray-a – wartość większa niż jeden oznacza podwójny klik. Przy pierwszy klik-u zostaje uruchomiony timer i zwiększony licznik kliknięć. Jeżeli w ciągu sekundy nie nastąpi kolejne kliknięcie licznik i timer są resetowane.

Na koniec pozostaje pytanie – Dlaczego zabrakło obsługi właśnie tego zdarzenia w klasie SystemTrayIcon?

EDIT (08-08-2010): Do powyższego rozwiązania wkradł się niewielki błąd – jest to dość późna edycja, ale wcześniej brak chęci i czasu na blogowe poczynania. W metodzie „onClickTrayIcon” wywołanie event-a „doubleClick” odbywa się na instancji obiektu „SystemTrayIcon”. Przesłonięta została także metoda „addEventListener”.