Download: Programowanie_perl

Transkrypt

Download: Programowanie_perl
PROGRAMOWANIE
Perl
GUI Gtk i zapytania WWW z Perl Object Environment
Gracz zespołowy
Perl Object Environment (POE) dostarcza platformy dla tworzenia
skryptów, które maja wykonywać
tzw. cooperative multitasking bez
jakiejkolwiek pomocy ze strony
schedulera systemu operacyjnego.
Aplikacja, którą stworzymy w tym
miesiącu, umożliwi wykonywanie
z interfejsu Gtk czasochłonnych zapytań WWW.
MICHAEL SCHILLI
A
plikacje GUI są zwykle sterowane
wydarzeniami. Typowy program
będzie posiadał główną pętlę, której używa do oczekiwania na wydarzenia,
takie jak kliknięcia myszy czy znaki wpisywane z klawiatury. Istotne jest przy tym,
aby program przetwarzał te zdarzenia bez
opóźnień i szybko powracał do głównej pętli. To sprawia, że użytkownik nie zauważa
chwilowego barku dostęp do interfejsu.
Ticker wyświetlający ceny akcji, któremu
przyjrzymy się w tym miesiącu, okresowo
łączy się z serwisem finansowym portalu
Yahoo, żeby pobrać ceny akcji (Rysunek 1).
W zależności od jakości połączenia sieciowego, żądanie rozwiązania nazwy DNS może zająć nawet kilka sekund. Mimo to
chciałbym, żeby mój program w tym czasie
nadal wyświetlał swój interfejs normalnie
pracując.
Programiści używają w takich wypadkach wielowątkowości i wielozadaniowości.
Jednak obydwie techniki są zbyt skomplikowane do naszego zastosowania. Krytyczne części danych muszą być chronione
przed równoczesnym dostępem, co sprawia
też, że wyszukiwanie błędów jest bardzo
78
Maj 2004
trudne. Jeśli kiedykolwiek musieliście analizować zrzut pamięci z 200 aktywnymi
wątkami, na pewno wiesz co mam na myśli.
Jest metoda na uniknięcie tych problemów – tzw. cooperative multitasking z POE
– Perl Object Environment [2], którego
głównym twórcą jest Rocco Caputo. Środowisko zostało zaimplementowane jako maszyna stanu, które i tak wykonuje dokładnie jeden proces w jednym wątku, ale dla
aplikacji użytkownika „jądro” umożliwia
uruchamianie wielu zadań w trybie semi-równoległym.
Ręka na pulsie
Programiści, którzy chcą zadawać zapytania na temat cen akcji z poziomu skryptu
Perl, zazwyczaj używają modułu CPAN
o nazwie Yahoo::FinanceQuote:
use Finance::YahooQuote;
my @quote = U
getonequote($symbol);
Niestety, moduł pracuje synchronicznie i to
bardzo utrudnia osiągnięcie płynności przy
przewijaniu. Funkcja getonequote wysyła
www.linux-magazine.pl
zapytanie HTTP do serwera Yahoo server,
oczekuje na odpowiedź i zwraca rezultaty.
Jednak my chcemy, żeby wyświetlanie
w naszym programie było płynne i nie było
blokowane przez oczekiwanie – zgodnie
z prawem Murphy'ego, ktoś na pewno przeciągnie inne okno ponad naszym tickerem.
W takim przypadku aplikacja powinna
przerysować swój interfejs, żeby odświeżyć
widok okna, jednak ponieważ program
oczekuje na wyniki zapytania HTTP, nie
zrobi tego, a jedynie pozostawi paskdny,
pusty i szary prostokąt na pulpicie. Słowem
kompromitacja dla autora.
Podejście asynchroniczne
Byłoby bardziej elegancko przekazać żądanie WWW i powrócić do odświeżania GUI
bez oczekiwania na rezultaty. Kiedy nadejdzie wreszcie odpowiedź z serwera Yahoo,
powinien zostać wygenerowany swoisty
alarm. To oznacza szybką aktualizację okna
tickera i „wskoczenie” z powrotem do głównej pętli GUI.
Dokładnie tak działa POE. Dostarcza jądro, gdzie poszczególne aplikacje rejestrują
swoje sesje i maszyna stanu przełącza się
Perl
zwracana do jądra. Maszyna stanu
przechodzi w stan wake_up co
każde 60 sekund (poprzez alarm)
lub gdy ktoś kliknie przycisk
Update w GUI. Uruchamia to kolejną maszynę stanu POE::Component::Client::HTTP i natychmiast przekazuje kontrolę z powrotem do jądra.
Rysunek 1:
PoCoCli::HTTP to tak zwany
Dane
Oparty na GTK
w ostatniej kolejności ticker pokazują- komponent POE: maszyna stanu,
która definiuje swoją własną sesję
Mimo że operacje odczytu i zapisu
cy ceny akcji łą(nazywaną useragent, patrz Listing
nie są na razie asynchroniczne
czy się co pewien
2, linia 73), przyjmuje zapytania
(POE po prostu używa nieblokujączas ze serwisem
WWW w stanie request i przełącza
cych funkcji syswrite lub sysread),
finansowym porsię do POE dopóki nie otrzyma pełdowolna informacja jest przekazytalu Yahoo.
nej odpowiedzi HTTP. W tym mowana dalej bardzo szybko. Aspekt
mencie useragent sprawia, że kernel powoduje,
kooperatywny POE wynika stąd, że sesje poleiż sesja wywołująca ticker przełącza się w stan
gają na konkurujących sesjach. Jeśli zadanie
yhoo_response, który był przekazany poprzednie zajmie permanentnie procesora, sesja munio do useragent.
si przekazać kontrolę z powrotem do kernela.
Kernel przełącza stan sesji ticker i sesja akMultitasking w ramach pojedynczego
ceptuje odpowiedzi HTTP, odświeża widget
wątku znacząco ułatwia rozwój aplikacji,
cen akcji w GUI i przekazuje kontrolę z ponie trzeba martwić się o blokowanie dostęwrotem do kernela. In line 69, the POE::Compu, a jeśli pojawi się błąd, to jest on łatwy
ponent::Client::HTTP uruchamia spawn()
do zlokalizowania. POE będzie współpracoi powoduje, że łańcuch gtkticker/0.01 pojawia
wać z główną pętlą zdarzeń. POE rozpoznasię po stronie serwera jako UserAgent i wreszje Perl/Tk i gtkperl automatycznie oraz incie ustawia timeout na 60 sekund.
tegruje się z nimi bez problemu. Dzięki temu kernel może przypisać poszczególnym
zdarzeniom szczeliny czasowe, tak jak jawPodręcznik Yahoo
nie zdefiniowanym sesjom. Jest to zatem
Linie 10-21 z Listingu 2 określają URL do
odpowiedź dotycząca odświeżania.
serwisu z kursami prowadzonego przez portal Yahoo. Interfejs CGI tego serwisu oczekuje dwóch parametrów:
Alarmowanie jądra
Ticker używa maszyny stanu POE::Session,
■ parametru określającego format (f=),
jak pokazano na Rysunku 2. Faza inicjalizaktóry formatuje poszczególne pola użycji, _start generuje interfejs GTK i ustawia
wając następujących nazw: s (symbol),
alias sesji na ticker, co umożliwi nam łatwe
l1 (cena akcji) i c1 (procentowa zmiana
zidentyfikowanie sesji później. Kontrola jest
do ceny z poprzedniego dnia)
między stanami i wymienia wiadomości. Operacje I/O są asynchroniczne. Zamiast otwierania
pliku lub gniazda, proces może po
prostu powiedzieć „Hej kernel,
chcę odczytać pewne dane. Czy
możesz mnie obudzić, kiedy już
będą dostępne?”
PROGRAMOWANIE
Listing 1: Plik
konfiguracyjny
01
02
03
04
05
06
# ~/.gtkticker
TWX
MSFT
YHOO AMZN RHAT
DODGX
JNJ COKE IBM SUN
parametru określającego symbole, który zawiera listę skrótów reprezentujących akcje
poszczególnych firm. Skróty są rozdzielane
przecinkami np. YHOO, MSFT, TWX.
Serwer Yahoo odpowiada w następujący
sposób:
■
„YHOO”,45.38,+0.35
„MSFT”,27.56,+0.19
„TWX”,18.21,+0.75
Gtkticker przyjmuje odpowiedź – linia po
linii, używa przecinków do rozdzielania
łańcuchów znaków i łączy dane przygotowując je do wyświetlania w GUI.
Konfiguracja
katalogu domowego
Wiersze 13 i 14 określają gtkicker w katalogu domowym użytkownika jako plik symbolu wyświetlany przez ticker. Wiersze od 30
do 37 przetwarzają plik, wiersz po wierszu,
pomijając wiersze zaczynające się od #, co
jest traktowane jako komentarz (wiersz 33).
Jawna pętla for znajduje się w wierszu 35
... for /(\S+)/g;
wykonuje się ona na wszystkich słowach
Prenumerata Linux Magazine
Nie przegap takiej okazji
■ Zamawiając prenumeratęoszczędzasz!
■ Płacisz jak za 9 numerów, a otrzymujesz 12!
■ Z każdym numerem DVD
lub płyta CD-ROM.
Najszybszy sposób zamówienia prenumeraty:
http://www.linux-magazine.pl
Infolinia: 0801-800-105
PROGRAMOWANIE
Perl
znajdujących się w linii (począwszy od lewej)
i symbol jest umieszczany w zmiennej $_.
Funkcja push układa skróty nazw akcji w tablicy @SYMBOLS – umożliwia to zapis wielu symboli w jednej linii, oddzielonych spacjami. Listing 1 pokazuje przykładowy plik.
Pomimo użycia framework-u POE, gtkticker
wykorzystuje standardowe funkcje synchroniczne I/O do odczytu pliku konfiguracyjnego.
Taniec zacząć czas...
Linia 39 definiuje stan maszyny ticker. Parametr inline_states używa referencji przez hasz,
aby mapować funkcje na poszczególne stany.
Kernel będzie skakał do tych funkcji, jeśli maszyna wejdzie w odpowiedni stan. Linia 53
przełącza stan wake_up dla sesji ticker jądra
$poe_kernel->post('ticker', U
'wake_up');
poprzez zmienną $poe_kernel eksportowaną przez POE. Wiersz 55 uruchamia główną pętlę krenela
$poe_kernel->run();
w której program pozostaje do czasu jego
wyłączenia. I o to nam chodzi!
Konstrukcja obiektu POE::Session, pokazana poprzednio, ma pewien efekt uboczny.
Uruchamia procedurę start() zdefiniowaną
w linii 58, która mapuje stan _start. Powoduje
to ustawienie aliasa dla sesji ticker i wykonuje
skok do my_gtk_init(). Ta funkcja z kolei
(uruchamiana w linii 98) tworzy GUI GTK.
Budowanie GUI
z użyciem GTK
Gtk jest modułem CPAN autorstwa Marc-a
Listing 2: Program Gtkticker c.d.
001 #!/usr/bin/perl
002 #############################
003 # gtkticker
004 # Mike Schilli, 2004
005 # ([email protected])
006 #############################
007 use warnings;
008 use strict;
009
010 my $YHOO_URL =
011 "http://quote.yahoo.com/d?".
012 "f=sl1c1&s=";
013 my $RCFILE
=
014 "$ENV{HOME}/.gtkticker";
015 my @LABELS
= ();
016 my $UPD_INTERVAL = 60;
017 my @SYMBOLS;
018
019 use Gtk;
020 use POE qw(
021
Component::Client::HTTP);
022 use HTTP::Request;
023 use Log::Log4perl qw(:easy);
024 use Data::Dumper;
025
026 Log::Log4perl->easy_init(
027
$DEBUG);
028
029
# Odczytujemy plik
konfiguracyjny
030 open FILE, "<$RCFILE" or
031
die "Nie mogę otworzyć
pliku $RCFILE";
032 while(<FILE>) {
033
next if /^\s*#/;
034
push @SYMBOLS, $_
035
for /(\S+)/g;
036 }
037 close FILE;
038
039 POE::Session->create(
80
Maj 2004
040
041
042
043
},
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
www.linux-magazine.pl
inline_states => {
_start
=> \&start,
_stop
=> sub {
INFO "Zamykanie"
yhoo_response =>
\&resp_handler,
wake_up =>
\&wake_up_handler,
}
);
my $STATUS;
$poe_kernel->post(
"ticker", "wake_up");
$poe_kernel->run();
#############################
sub start {
#############################
DEBUG "Startujemy";
$poe_kernel->alias_set(
'ticker');
my_gtk_init();
$STATUS->set("Startujemy");
POE::Component::Client::HTTP
->spawn(
Agent
=>
'gtkticker/0.01',
Alias
=> 'useragent',
Timeout => 60,
);
}
#############################
sub upd_quotes {
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#############################
my $request =
HTTP::Request->new(
GET => $YHOO_URL .
join ",", @SYMBOLS);
$STATUS->set(
"Pobieram kursy");
$poe_kernel->post(
'useragent',
'request',
'yhoo_response',
$request);
}
#############################
sub my_gtk_init {
#############################
my $w = Gtk::Window->new();
$w->set_default_size(
150,200);
# Tworzymy menu
my $accel =
Gtk::AccelGroup->new();
$accel->attach($w);
my $factory =
Gtk::ItemFactory->new(
'Gtk::MenuBar',
"<main>", $accel);
$factory->create_items(
{ path => '/_File',
type => '<Branch>',
},
{ path
=>
'/_File/_Quit',
accelerator =>
Perl
Lehmann-a, który był również uprzejmy przejrzeć niniejszy artykuł. Obecnie moduł został
zastąpiony przez Gtk2, jednak nowa wersja ma
kilka problemów z POE. Tak czy inaczej, moduł GTK i tak wykonuje wspaniałą robotę.
Obiekt klasy Gtk::Window reprezentuje
główne okno aplikacji. Posiada ono typowy
pasek menu na górze dający dostęp do rozwijalnego menu File, które ma jedna opcję – Quit. Opcja ta używa procedury Gtk->exit(0) do
kończenia pracy programu. Jest także obiekt
Gtk::AccelGroup, który umożliwia zamknięcie programu przez wciśnięcie kombinacji
klawiszy [Ctrl]+[Q]. Obiekt tek dodaje tzw.
Akceleratory (kombinacje klawiszy).
Domyślne menu
Menu jest tworzone przez użycie klasy
Gtk::ItemFactory, która jest najpierw używana
to utworzenia paska menu Gtk::MenuBar. Pozycje menu i ewentualne podmenu są tworzone
przy użyciu metody create_items(). Parametr
path określa pozycję elementu menu – przykładowo, /_File/_Quit definiuje pozycję Quit poniżej File na pasku menu. Znak podkreślenia _
powoduje, że Gtk podkreśla daną literę, umoż-
PROGRAMOWANIE
liwiając użytkownikowi wciśnięcie skrótu klawiszowego (takiego jak [Alt]+[F]) do przemieszczania się po menu. Parametr callback
określa, że Gtk uruchomi akcję niezależnie od
tego, czy użytkownik wybierze pozycję w menu
myszą, czy wciśnie kombinację klawiszy zdefiniowaną przez parametr accelerator.
Menedżer wyglądu
Można stosować dwa sposoby do geometrycznego rozmieszczania widgetów: Gtk::VBox
i Gtk::Table. Kontener Gtk::VBox wyrównuje
zawarte w nim widgety pionowo. Metoda
Listing 2: Program Gtkticker c.d.
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
'<control>Q',
callback
=>
[sub { Gtk->exit(0) }],
});
my $vb = Gtk::VBox->new(
0,0);
my $upd = Gtk::Button->new(
'Update');
$vb->pack_start(
$factory->get_widget(
'<main>'), 0, 0, 0);
# Button at bottom
$vb->pack_end($upd,
0, 0, 0);
# Status line on top
# of buttons
$STATUS= Gtk::Label->new();
$STATUS->set_alignment(
0.5, 0.5);
$vb->pack_end($STATUS,
0, 0, 0);
my $table =
Gtk::Table->new(
scalar @SYMBOLS, 3);
$vb->pack_start($table,
1, 1, 0);
for my $row (0..
@SYMBOLS-1) {
for my $col (0..2) {
my $label =
Gtk::Label->new();
$label->set_alignment(
0.0, 0.5);
push @{$LABELS[$row]},
$label;
162
163
$table->attach_defaults(
164
$label, $col, $col+1,
165
$row, $row+1);
166
}
167
}
168
169
$w->add($vb);
170
171
# Niszczymy okno
172
$w->signal_connect(
173
'destroy', sub {
174
Gtk->exit(0)});
175
176
# Wciśnięcie przycisku
update
177
$upd->signal_connect(
178
'clicked', sub {
179
DEBUG "Wysyłam wakeup";
180
$poe_kernel->post(
181
'ticker', 'wake_up')}
182
);
183
$w->show_all();
184 }
185
186 #############################
187 sub resp_handler {
188 #############################
189
my ($req, $resp) =
190
map { $_->[0] }
191
@_[ARG0, ARG1];
192
193
if($resp->is_error()) {
194
ERROR $resp->message();
195
$STATUS->set(
196
$resp->message());
197
return 1;
198
}
199
200
DEBUG "Odpowiedź: ",
201
$resp->content();
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
my $count = 0;
for(split /\n/,
$resp->content()) {
my($symbol, $price,
$change) =
split /,/, $_;
chop $change;
$change = "" if
$change =~ /^0/;
$symbol =~ s/"//g;
$LABELS[$count][0]->
set($symbol);
$LABELS[$count][1]->
set($price);
$LABELS[$count][2]->
set($change);
$count++;
}
$STATUS->set("");
1;
}
#############################
sub wake_up_handler {
#############################
DEBUG("waking up");
# Initiate update
upd_quotes();
# Re-enable timer
$poe_kernel->delay(
'wake_up', $UPD_INTERVAL);
}
www.linux-magazine.pl
Maj 2004
81
PROGRAMOWANIE
Perl
pack_start() umieszcza elementy od góry do
dołu, podczas gdy pack_end() czyni to odwrotnie. Definicja
$vb->pack_start($menu_bar, U
$expand, $fill, $padding);
umieszcza pasek menu na górze Vbox-a.
W linii 132 gtkticker używa $factory>get_widget('<main>') do pobrania obiektu paska używając nazwy.
Parametr
$expand określa, czy obszar, który zajmuje
widget powinien się rozszerzać, jeśli użytkownik użyje myszy dla rozszerzenia głównego okna. Jeśli tak, to widget będzie również się powiększał – pozwoli to przyciskom
zwiększać się do dowolnych rozmiarów.
Wreszcie $padding określa minimalną ilość
pikseli, która powinna rozdzielać (pionowo)
widgety od siebie. Gtkticker wyświetla informacje o statusie poprzez widget Gtk::Label bezpośrednio nad przyciskiem Update.
Metoda set_alignment() używa następującej
składni
$STATUS->set_alignmentU
(0.5, 0.5);
żeby wykonać wyrównanie tekstu poziome
i pionowe. Jeśli chcemy eksperymentować,
wartość wyrównania poziomego 0.0 oznacza
wyrównanie do lewej, a 1.0 wyrównanie tekstu
do prawej. Dla kontrastu kontener Gtk::Table
daje programistom Perla narzędzie do wygodnego rozmieszczania widgetów w tabeli. Metoda attach_defaults() oczekuje pięciu parametrów: widgeta wzorcowego, do którego ma być
wyrównywany widget oraz dwóch kolumn
i współrzędnych, między którymi widget będzie umieszczony. Przykładowo,
$table->attach_defaultsU
($label, 0, 1, 1, 2);
Akcja!
Do widgetów Gtk::Button można przypisywać określone akcje. Gtk wykonuje akcję, gdy
użytkownik wciśnie przycisk. Metoda wywoływana w linii 177 – signal_connect(), określa, że Gtk powinno wysłać zdarzenie wake_up do jądra POE, gdy użytkownik kliknie
przycisk Update. Do głównego okna również
przypisano określoną akcję – użytkownicy
Maj 2004
$w->signal_connect('destroy',
sub {Gtk->exit(0)});
kończy sesję Gtk i zamyka program. Po zdefiniowaniu wszystkich widgetów, metoda
show_all() wyświetla je w oknie głównym (linia 183) na ekranie.
Kernel kontratakuje
W stanie yahoo_response jądro POE skacze
do funkcji pokazanej poniżej linii 187 –
resp_handler. Z definicji POE::Component::Client::HTTP będzie przechowywać
pakiety zapytania i odpowiedzi w ARG0
i ARG1, gdy dojdzie do takiego skoku. POE
wykorzystuje nieco dziwny sposób przekazywania parametrów po wprowadzeniu kilku
nowych funkcji reprezentujących stałe liczbowe, takich jak KERNEL, HEAP, ARG0,
ARG1. Autorzy POE oczekują, że programiści użyją ich do indeksowania tabeli parametrów funkcji @_. Przykładowo, $_[KERNEL] zawsze zwróci obiekt kernela, którego
indeks wskazuje KERNEL.
Wspomniane pakiety z pytaniami i odpowiedziami są referencjami do tablic, które
przechowują obiekty HTTP::Request lub
HTTP::Response. Wreszcie polecenie map
z wiersza 190 dokonuje ekstrakcji danych do
$req i $resp. Jeśli pojawi się błąd HTTP, linia
195 wygeneruje odpowiednią wiadomość
w oknie statusu widgeta i dla wartości zwracanej przez funkcję. W innym przypadku globalna, dwuwymiarowa tablica etykiet przycisków jest odświeżana. Widgety wyświetlają
symbole akcji, cenę bieżącą oraz zmianę procentową ceny (przypadek szczególny – zmiana 0% jest ignorowany).
Alarmy okresowo opóźnione
określa, że dla element $label obiektu Gtk::Label zostanie dodany do pierwszego wiersza
(„między 0 i 1”) i drugiej kolumny („między
1 i 2”) tabeli wskazywanej przez $table.
82
mogą kliknąć krzyżyk na pasku tytułowym
okna, aby zakończyć pracę aplikacji.
Zdarzenie wake_up wywołuje w jądrze POE
procedurę wake_up_handler(), zdefiniowaną
w wierszu 232 i następnych. Wywołuje też
funkcję upd_quotes(), która jest zaimplementowana w wierszu 79 i kolejnych. Funkcja definiuje obiekt HTTP::Request i używając zdarzenia przesyła go do komponentu
POE::Component::Client::HTTP. Docelowy
stan dla ticker jest ustawiony na yahoo_response. Po wykonaniu tych czynności przygotowawczych, wake_up_handler() używa
zaimplementowanej w jądrze metody delay()
do wysłania alarmu. To z kolei powoduje, że
zdarzenie wake_up jest wywoływane w sesji
ticker, gdy minie określona liczba sekund
www.linux-magazine.pl
zdefiniowana w $UPD_INTERVAL (w naszym przypadku to 60 sekund). Od tego momentu ticker aktualizuje ceny akcji co każde
60 sekund, bez potrzeby wciskania przycisku
Update przez użytkownika.
Instalacja
Najlepszym sposobem na zainstalowanie niezbędnych pakietów POE oraz POE::Component::Client::HTTP jest użycie powłoki
CPAN. Jeśli zostanie również instalowany moduł POE::Component::Client::DNS, zapytania
DNS będą wykonywane asynchronicznie;
w przeciwnym wypadku wykonywanie funkcji
gethostbyname() powodowałoby opóźnienia.
Instalacja Gtk z archiwów CPAN oznacza,
że trzeba rozwiązać kilka zależności między
pakietami, prowadzi to zazwyczaj do różnych
problemów w zależności od używanego systemu. Jednak wykonanie poleceń
touch./Gtk/build/U
perl-gtk-ref.pod
perl Makefile.PL U
--without-guessing
w katalogu dystrybucyjnym, a następnie
uruchomienie make install rozwiązało
wszystkie problemy. Skrypt loguje informacje do debuggowania na standardowe wyjście (STDOUT), jeśli jest to problemem,
można przekierować logowanie używając
pakietu Log::Log4perl (również z CPAN)
i zamieniając w wierszu 27 $DEBUG na
$ERROR. Niezwykłe, jak szybko to działa.
Nawet jeśli aplikacja wykonuje automatyczną aktualizację przez powolną sieć,
GUI nie jest blokowane. A wszystko takie
łatwe do zaimplementowania!
■
INFO
[1] Listingi dla artykułu:
http://www.linux-magazine.com/Magazine/
Downloads/42/Perl/
[2] POE: http://poe.perl.org
[3] Jeffrey Goff, „A Beginner’s Introduction
to POE”, 2001: http://www.perl.com/
pub/a/2001/01/poe.html
[4] Matt Sergeant, „Programming POE”,
talk at TPC 2002: http://axkit.org/docs/
presentations/tpc2002
[5] Gtkperl: http://gtkperl.org
[6] Tutorial Gtkperl:
http://personal.riverusers.com/
~swilhelm/gtkperl-tutorial/
[7] Eric Harlow, „Developing Linux Applications
with GTK+ and GDK”: New Riders, 1999,
ISBN 0735700214

Podobne dokumenty