LINUXSOFT.cz Přeskoč levou lištu
Uživatel: Heslo:  
   CZUKPL

> Perl (124) - Gtk2 - události a čas

Perl S událostmi a časem již máme z předchozích grafických toolkitů nějaké zkušenosti. Jak k této oblasti ale přistupuje Gtk2?

5.1.2011 00:00 | Jiří Václavík | Články autora | přečteno 4368×

Události

Představme si, že program právě vykonává Gtk2::main a čeká na události. Jakmile nastane událost (událostí se rozumí například stisk klávesy, pohyb myší do nějakého daného prostoru atd.), emituje se signál. Tyto signály mohou být emitovány různými widgety a existuje jich řada druhů, podle toho, jak byly vyvolány. S nejběžnějšími se v seriálu postupně seznámíme.

Signály budeme odchytávat. Pokud signál neodchytneme, nic se nestane. Událost nezpůsobí žádnou akci. To se děje velmi často, neboť to prostě nemusí být potřeba. Pro uvědomění si zkuste například teď v internetovém prohlížeči stisknout klávesu ESC. Ve většině prohlížečů na tuto událost není definována reakce, tudíž se vůbec nic nestane. Navíc signálů se i v jednoduché aplikaci emituje obrovské množství.

Pokud ale uživatel například klikne na tlačítko nebo provede jinou událost, od které je nějaká návazná činnost očekávána, měli bychom se postarat o to, aby byla příslušná akce provedena. To je případ, který nás zajímá.

Signály se obvykle odchytávají voláním nějaké funkce, která se nám o to postará. Musíme jí však sdělit několik věcí, aby věděla, co přesně po ní chceme.

  • určit widget, který emitoval signál
  • určit signál, na který chceme reagovat
  • jak chceme reagovat (tj. odkaz na nějakou funkci [tzv. callback funkci], která se provede)
  • případně něco dalšího - přepínače, parametry atd.

Callback funkce je obyčejný podprogram. Může být buď anonymní nebo pojmenovaný.

Ten pojmenovaný obvykle jako parametry dostane objekt reprezentující widget, který vyvolal signál, a případné parametry. Vypadá nějak takto.

sub akce {
    my($self, $parametr) = @_;
    #provedení akce
}

Signál obvykle propojujeme s akcí příkazem signal_connect, který dodržuje tuto strukturu.

$widget->signal_connect(typ_signalu => \&akce, $parametry);

Akce lze samozřejmě také modifikovat. Pro zrušení spojení signálu a akce lze použít metodu signal_handler_disconnect.

Příklad události - kliknutí na tlačítko

Upravíme náš program s tlačítkem tak, aby získalo funkcionalitu. Budeme chtít, aby se po stisknutí ukončila aplikace. Jinými slovy chceme, aby se po stisku tlačítka provedl podprogram konec, který vypadá takto.

sub konec {
    my($widget) = @_;
    Gtk2->main_quit;
}

Poznamenejme, že příkaz Gtk2->main_quit končí smyčku událostí a tedy v našem případě i celý program (ale kdybychom dále opět volali Gtk2->main, celá smyčka by se rozběhla nanovo).

Propojme tedy emitovaný signál s naším podprogramem. Použijme metodu signal_connect zavolanou nad tlačítkem. Po stisku tlačítka se vždy emituje signál clicked.

$tlacitko->signal_connect(clicked => \&konec);

Upravili jsme tedy celý program do následující podoby.

use Gtk2;
Gtk2->init;

sub konec {
    my($widget) = @_;
    Gtk2->main_quit;
}


$okno = Gtk2::Window->new("toplevel");
$okno->set_border_width(20);

$tlacitko = Gtk2::Button->new("Konec");
$tlacitko->signal_connect(clicked => \&konec);
$okno->add($tlacitko);

$tlacitko->show;
$okno->show;

Gtk2->main;

Proč se při zavření okna neukončí aplikace?

Gtk2 má tu vlastnost, že, zavřeme-li hlavní okno, aplikace běží dál. Na tom není nic špatného, ale ve většině případů budeme chtít aplikaci v takové situaci tak jako tak ukončit. Nyní to je třeba udělat například posláním SIGTERM, což není příliš elegantní řešení. Jak docílíme nápravy?

Existuje signál delete_event. Ten se emituje v reakci na událost zavření hlavního okna. Jednoduchým trikem zajistíme, aby se při emitaci delete_event celá aplikace ukončila.

$okno->signal_connect(delete_event => sub{Gtk2->main_quit});

Příklad - detekce stisknuté klávesy

Pomocí signálu key-press-event lze zachytávat klávesy z klávesnice. Zkusme tedy vytvořit akci, která proběhne po stisku libovolné klávesy. Budeme chtít vypsat nějakou informaci o stisknuté klávese.

$okno->signal_connect("key-press-event" => \&info);

Informaci budeme vypisovat pomocí popisku, který vytvoříme následovně.

$label = Gtk2::Label->new();

Jeho text pak nastavujeme pomocí set_markup.

$label->set_markup("Ahoj");

Podprogram info dostane jako parametr událost. Z ní můžeme získat id klávesy (metodou keyval). Máme k dispozici také hash %Gtk2::Gdk::Keysyms, který každé klávese přiřazuje nějaké id. Podívejme se pro zajímavost na část dat z tohoto hashe.

...
"downarrow" => 2302,
"Greek_chi" => 2039,
"ISO_Level2_Latch" => 65026,
"doubledagger" => 2802,
"guillemotleft" => 171,
"w" => 119,
"Pointer_Drag_Dflt" => 65268,
"threequarters" => 190,
"Hangul_Hanja" => 65332,
"cedilla" => 184,
"Armenian_e" => 16778599,
"MouseKeys_Enable" => 65142,
...

Z něj můžeme získat název stisknuté klávesy.

Podívejme se tedy na program, který nás informuje o událostech z klávesnice.

use Gtk2::Gdk::Keysyms;
use Gtk2 "-init";

sub info {
    my($widget, $udalost)= @_;
    my $id = $udalost->keyval;
    for $k (keys %Gtk2::Gdk::Keysyms){
        $label->set_markup("Stisknuto $k ($id)") if $Gtk2::Gdk::Keysyms{$k} == $id);
    }
    return 0;
}

$okno = Gtk2::Window->new("toplevel");
$okno->signal_connect("key-press-event" => \&info);
$label = Gtk2::Label->new();
$okno->add($label);
$okno->show_all;
Gtk2->main;

Uděláme ještě drobnou úpravu ve zdrojovém kódu, abychom se vyhnuli používání globálních proměnných. Při reakci na signál si necháme jako parametr předat label, který budeme modifikovat.

use Gtk2::Gdk::Keysyms;
use Gtk2 "-init";

sub info {
    my($widget, $udalost, $label)= @_;
    my $id = $udalost->keyval;
    for $k (keys %Gtk2::Gdk::Keysyms){
        $label->set_markup("Stisknuto $k ($id)") if $Gtk2::Gdk::Keysyms{$k} == $id);
    }
    return 0;
}

$okno = Gtk2::Window->new("toplevel");
$label = Gtk2::Label->new();
$okno->signal_connect("key-press-event" => \&info, $label);
$okno->add($label);
$okno->show_all;
Gtk2->main;

Výsledek vidíme na obrázku.

Po stisku w *** po stisku caps lock

Řekněme na tomto místě ne úplně související poznámku. Všimněme si závěru programu. Abychom nemuseli volat metodu show nad každým widgetem, lze použít místo všech těchto volání metodu show_all.

$okno->show_all;

Příklad - tlačítka myši

Druhou důležitou skupinou signálů jsou ty, které byly emitovány událostmi myši. Signál button-release-event se vyvolá po kliknutí na daný widget.

Vytvořme si tlačítko, na které bude uživatel klikat. My budeme pro informaci vypisovat, které tlačítko myši uživatel stiskl.

Všechny potřebné věci již umíme a tak se podívejme na zdrojový kód této aplikace. Dodejme jen, že nad objektem události (ten dostaneme v callback funkci jako parametr) voláme metodu button, která nám vrací id tlačítka myši.

use Gtk2 "-init";

$okno = Gtk2::Window->new ("toplevel");
$vbox = Gtk2::VBox->new(0, 5);
$tlacitko = Gtk2::Button->new("Klikni");
$label = Gtk2::Label->new();

$tlacitko->signal_connect("button-release-event" => sub {
    $label->set_markup("stisknuto ".$_[1]->button().". tlacitko mysi");
});

$vbox->pack_start($tlacitko, 1, 1, 0);
$vbox->pack_start($label, 1, 1, 0);
$okno->add($vbox);
$okno->show_all;

Gtk2->main;

Klikáme-li na tlačítko, můžeme pozorovat následující akce.

Po stisku 2. tlačítka myši *** po stisku 3. tlačítka myši

Čas

Pomocí Glib::Timeout lze nastavovat akce, které se budou periodicky vykonávat. Metodou add přidáváme úlohu. Uvádíme zde interval opakování v milisekundách, podprogram, který se má provést, a případně parametr a prioritu. Dokud podprogram nevrátí false, bude se jeho vykonávání opakovat.

Glib::Timeout->add(1000, \&akce, $parametr);

Verze pro tisk

pridej.cz

 

DISKUZE

Nejsou žádné diskuzní příspěvky u dané položky.



Příspívat do diskuze mohou pouze registrovaní uživatelé.
> Vyhledávání software
> Vyhledávání článků

16.9.2014 5:08 /MaReK Olšavský
VESA uvolnila technický standard DisplayPort 1.3. DP 1.3 má šířku pásma 32,1 Gb/s, což je dostatečný tok na 5k display při frekvenci 60 Hz. Technicky by se mohlo HDMI, populární především u spotřební elektroniky, stát historickou kapitolou (DP není zatížen licenčními poplatky).
Přidat komentář

16.9.2014 5:08 /MaReK Olšavský
SUSE (a další značky včetně Novellu) mají zase jiného majitele, Attachmate byla koupena společností Micro Focus za US$ 2,3 mld. Micro Focus se dosud věnoval enteprise sféře a nástroji Visual COBOL.
Přidat komentář

16.9.2014 5:08 /MaReK Olšavský
Finální verze Enlightenment 19 byla dokončena a hlavním tahákem je plná podpora nastupujícího Waylandu. Z dalších změn může zaujmout nový modul dlaždic, modul pro integraci správce balíků, nebo návrat live pageru (známého z E16). Po dlouhých letech stagnace se Enlightenment začal zajímavě vyvíjet.
Přidat komentář

15.9.2014 22:25 /Petr Ježek
Enlightenment E19 přistál v repozitáři Testing pro Archlinux. Testování lze jen doporučit.
Přidat komentář

15.9.2014 7:25 /MaReK Olšavský
Verze 3.0 a existence repozitářů do dubna 2015 budou to poslední, co bude provázet konec projektu Bohdi Linux ze strany jeho maintainera Jeffa Hooglanda. V projektu forku Ubuntu s desktopem Enlightenment může pokračovat kdokoliv další, ale najde se někdo?
Komentářů: 2

15.9.2014 7:25 /MaReK Olšavský
S Tizenem začalo počítat BMW, které připravuje možnost dálkového ovládání.
Přidat komentář

12.9.2014 7:14 /MaReK Olšavský
ZFS, z dílen někdejšího SUN Microsystems, později portovaný i na *BSD, je připraven k produkčnímu nasazení na GNU/Linuxu. Pro GNU/Linux je vyvíjen i btrfs, který nabízí stejně pokročilé možnosti a jeho podpora je přímo v jádře.
Přidat komentář

12.9.2014 7:14 /MaReK Olšavský
Další město, které ukončení života Windows XP přechodem na některou z distribucí GNU/Linuxu bude italský Turín, kde si vybrali Ubuntu. Doufají v úsporu cca 6 mil. €.
Přidat komentář

   Více ...   Přidat zprávičku

> Poslední diskuze

16.9.2014 3:49 / MaReK Olšavský
Re: Těžko

15.9.2014 14:35 / Petr Ježek
Těžko

14.9.2014 11:04 / Petr Ježek
DE, ne WM

12.9.2014 12:09 / Thomas Jones
Great

9.9.2014 15:58 / František Kučera
Re: Díky za článek

Více ...

ISSN 1801-3805 | Provozovatel: Pavel Kysilka, IČ: 72868490 (2003-2014) | mail at linuxsoft dot cz | Design: www.megadesign.cz | Textová verze | zákony online