Своё знакомство с SWHX я решил начать с создания простого, но полезного приложения, аналогом которого довольно часто пользуюсь при работе в Ubuntu - там в Gnome есть возможность поставить себе регулярное напоминание о том, что пора отдохнуть, блокирующее экран на заданное время, дабы сберечь свои глаза.
Для этих же целей пока служит и EyeTimer (в будущем собираюсь построить на его основе более сложное и интересное приложение), так что теперь у меня будет такое же приложение и под Windows в которой приходится работать гораздо чаще и дольше (а если понадобится, то и для Mac, SWHX позволяет), но уже своё собственное, что, конечно, приятно.
Суть работы EyeTimer проста - при запуске вы задаёте время работы и отдыха в минутах и приложения чередует периоды, во время отдыха перекрывая экран полу-прозрачным flash окном с отсчётом оставшегося на отдых времени, тем самым помогая вам спасти себя от всяких непритных вещей типа "сухого глаза" и просто слишком долгого сидения за компьютером.
Заканчиваем с лирикой, переходим к технической части.
Итак, EyeTimer построен на основе SWHX - библиотеки для создания десктоп приложений, использующих Flash в качестве основы для интерфейса.
Flash интерфейс я сделал на платформе flash9, а в качестве GUI-библиотеки использовал Arctic. В принципе, с таким же успехом (а может и проще) было использовать готовый отрисованный UI или Flex, но мне нравится Arctic, так что я заодно решил в нём ещё раз попрактиковаться.
Если вдруг кто-то не знает как устанавливать библиотеки для haXe, могу сказать, что это очень сложно :)
haxelib install swhx
haxelib install arctic
Ссылка на архив с приложением и исходниками прилагается к этой странице (в самом низу), а здесь размещу код только одного из двух классов, того, что компилируется в neko и является сервером для EyeTimer:
import neko.net.RemotingServer;
import systools.win.Events;
import swhx.MessageHook;
import systools.Key;
import systools.Misc;
import swhx.Window;
class App
{
static var server :RemotingServer;
static var window :swhx.Window; // окно приложения
static var flash :swhx.Flash; // объект flash
static var cnx :swhx.Connection; // соединение с flash UI
static var keyboardHook :MessageHook;
static var WORK_TIME :Float = 45;
static var REST_TIME :Float = 15;
static var CANCEL_TIME :Float = 15; // время на которое откладывается отдых (сек)
static function main()
{
swhx.Application.init();
var screen = systools.Display.getScreenSize();
window = new swhx.Window( "Time to...", screen.w, screen.h, Window.WF_ALWAYS_ONTOP | Window.WF_PLAIN | swhx.Window.WF_TRANSPARENT );
window.onRightClick = function() { return false; }; // блок контекстного меню flash
server = new RemotingServer();
server.addObject("serverSide", App);
flash = new swhx.Flash( window, server );
flash.setAttribute( "src", "win.swf" );
flash.setAttribute( "FlashVars", "worktime="+WORK_TIME+"&resttime="+REST_TIME );
flash.onSourceLoaded = onSourceLoaded;
flash.start();
// хук для отлова событий клавиатуры:
keyboardHook = window.addMessageHook(untyped Events.KEYDOWN);
keyboardHook.setNekoCallback(keyDownHook);
window.visible = true;
swhx.Application.loop();
}
static function onSourceLoaded() {
cnx = swhx.Connection.flashConnect(flash);
}
// посылает клиенту команду показать окно конфигурации
static function showConfigWindow ()
{
cnx.Win.showConfig.call([WORK_TIME, REST_TIME]);
window.visible = true;
}
// посылает клиенту команду открыть заставку и запустить таймер отдыха
static function startRestWindow ()
{
cnx.Win.startRestTimer.call([REST_TIME]);
window.visible = true;
}
// -------------- обработчики --------------
// вызывается с клиента нажатием кнопки Start (запустить программу из конфига)
static function onStartWork (?wtime, ?rtime)
{
trace('onStartWork');
if (wtime != 0) WORK_TIME = wtime *60;
if (rtime != 0) REST_TIME = rtime *60;
window.visible = false;
setTimeout(startRestWindow, WORK_TIME);
}
// вызывается с клиента нажатием кнопки Cancel (отложить отдых)
static function onCancel ()
{
window.visible = false;
setTimeout(startRestWindow, CANCEL_TIME);
}
// обработчик нажатий на клавиатуру
static function keyDownHook() {
if (Misc.getKeyState(Key.Custom(27))) cleanUp(); // Esc
return 0;
}
// ------------ внутренние --------------------
// очистка ресурсов перед выгрузкой приложения
static private function cleanUp () {
window.removeMessageHook(keyboardHook);
window.removeMessageHook(rbuttonHook);
swhx.Application.cleanup();
}
//
static private function setTimeout(action, timeout)
{
neko.vm.Thread.create(
function () {
neko.Sys.sleep(timeout);
action();
}
);
}
}