Tuesday, November 11, 2008

Jython - przydatny, bez szału

Wczoraj musiałem napisać malutką, multiplatformową aplikacyjkę. Chodziło o niewielką ikonkę w trayu, podpięte do niej menu z opcją "&Zamknij". Ikonka w zależności od zawartości pewnej witryny miała się zmieniać na kolorową lub czarnobiałą.

Z jednej strony chciałem napisać to w Pythonie: przenośność, prosta składnia, czytelność - po części znane mi biblioteki. Z drugiej nie chciałem użerać się z wxWidgets, którego w ogóle nie znam. Muszę przyznać, że moim faworytem do interfejsów jest zdecydowanie Java. Już samo Swing jest bardzo dobrze zaprojektowanym rozwiązaniem jednak jeżeli dorzucić do tego możliwość pisania kodu z SWT - bije chyba wszystkie inne rozwiązania na głowę. Ponieważ zależało mi na estetyce aplikacji pod wieloma systemami - Java wygrywała przede wszystkim na tym polu.

I tutaj pojawia się właśnie pomysł na użycie jythona. Idea okazała się bardzo prosta. Używanie składni Pythona do modułów Java. Na początku bardzo miłe zaskoczenie:

from org.eclipse.swt.widgets import *

po prostu szok. Normalna biblioteka Java a ja tu sobie ją importuję po pythonowemu. Super ! Zaraz potem mogłem sobie zrobić:

import urllib

i wszystko działało :) Zmiana implementacji pojawiła się przede wszystkim przy listenerach - gdzie nie mogłem tworzyć klas "in place" jak w Javie, ale musiałem tworzyć własne - dziedziczące po tych mi potrzebnych. Jednak to raczej wpłynęło na Pythonowo rozumianą czytelność programu. Co do struktury początkowej ten kto pisał w SWT na pewno się połapie:

class App(object):

    def __init__(self):

        """Główny kod aplikacji."""

        self.display = Display()
        self.shell = Shell(self.display)

self.setTrayIcon()
self.createMenuItems()

        self.timer = Timer(self.display, self.image, self.tray, self.trayItem)
        self.timer.checkIsUndoneTickets()
        self.display.timerExec(5 * 1000, self.timer)

        while not self.shell.isDisposed():
            if not self.display.readAndDispatch():
                self.display.sleep()
                
        self.display.dispose()
        
if __name__ == '__main__':
    App()

Moim zdaniem banalne i genialne zarazem :] Właściwie - to samo co w języku Java tylko zapisane z użyciem innej składni.

Niestety nawet w tak banalnym programiku odczułem kilka podstawowych rzeczy. Na początku chciałem użyć Timera Pythonowego. Nie mógł on jednak komunikować się  z wątkiem głównego programu - SWT. Cóż, zmuszony byłem wykorzystać ten SWTowy.

Kolejna rzecz. Mój program wymaga otworzenia domyślnej przeglądarki systemu. Po trafieniu na moduł webbrowser Pythona już się cieszyłem, gdy zauważyłem, że niestety w Jythonie jest on niedostępny. Tak więc zmuszony byłem po raz kolejny użyć Javy.

Desktop.getDesktop().browse(URI(ratunkuAdminURL))
Dodatkowo powyższy kod działa tylko po części tak jak chciałem. Otwiera mi firefox-a w systemie, w którym domyślną jest Chrome. Powyższy kod bazuje na składnikach przestażałej już w wielu miejscach biblioteki awt. Jestem ciekaw czy nie istnieje możliwość zrobienia tego samego lepiej w Java :]

2 comments:

Anonymous said...

tak z ciekawości - jak rozwiązałeś dostęp jythona do swt.jar - ustawiałeś zmienną środowiskową CLASSPATH ?

Johny JKJK said...

Skorzystałem z tego opisu:
http://www.jcontrol.org/download/readme_eclipse_en.html

I chyba skopiowanie do odpowiednich katalogów Java jest rzeczywiście najrozsądniejsze.