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 5119×

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ů

22.5.2015 18:20 /Petr Ježek
Vyšel Systemd 220 s řadou změn. Český podíl na vývoji je nezanedbatelný. Je otázka, jak se změny dotknou jednotlivých distribucí.
Přidat komentář

15.5.2015 21:33 /MaReK Olšavský
Ve vývojových laboratořích Mozilly byla dokončena specifikace a implementace Rust 1.0. Jde o první (finální) vydání nového jazyka, který je od počátku deklarován, jako bezpečný a praktický. Už v něm někdo pracuje?
Přidat komentář

15.5.2015 7:18 /MaReK Olšavský
2×mikropočítače: První verze Raspberry Pi B+ je nyní ve slevě, prodává se za US$ 25. Velký úspěch zaznamenali vývojáři počítače CHIP, s cenou US$ 9, když crownfundingový cíl US$ 1 mil. dosáhli za 4 dny, bohužel pro nás bude dostupnost limitována značným poštovným.
Přidat komentář

13.5.2015 18:21 /Redakce Linuxsoft.cz
PR: Dne 21.5.2015 proběhne v Praze konference Firemní informační systémy. Tématy bude např. využívání informačních systémů v cloudu, mobilní přístup k firemním datům nebo bezpapírová firma.
Přidat komentář

4.5.2015 22:44 /Petr Ježek
Malý odklad Alfa verze Waylandu a Westonu 1.8 z důvodu konferenčního zaneprázdnění vývojáře ze Samsungu nic nemění na plánovaném datu vydání finální verze 29.5.2015.
Přidat komentář

26.4.2015 6:26 /MaReK Olšavský
Vyšel Debian 8.0 „Jessie“, označený jako LTS, tj. s 5 letou podporou. Podporuje 10 hlavních architektur, včetně Power (kterou většina hlavních distribucí již zavrhla), má přepracovánu podporu UEFI a také přešla na Systemd (sysvinit je alternativně k dispozici).
Přidat komentář

24.4.2015 9:31 /MaReK Olšavský
Nastal další „Den U“, neboli vydání aktuálních verze Ubuntu 15.04 i „spinů“ (Kubuntu, Xubuntu, Ubuntu MATE 15.04 a dalších). Jádro je řady 3.19, Upstart byl nahrazen moderním systemd (alternativně lze Upstart využít).
Přidat komentář

23.4.2015 8:33 /MaReK Olšavský
Jakub Jelínek ohlásil vydání GCC 5.1, již s podporou C++11 (kompletní i v stdlibc) a C++14 (na front-endu). Mezi dalšími novinkami je i podpora OpenMP 4.0, experimentální GCC JIT, nebo podporu OpenACC.
Přidat komentář

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

> Poslední diskuze

24.5.2015 20:58 / Jiří Zelinka
Re: Oživenie starého stroja

16.5.2015 11:22 / lmp
Oživenie starého stroja

28.4.2015 21:23 / Ondřej Čečák
Jeste dva dny

3.3.2015 22:05 / MaReK Olšavský
Re: Presmerovanie na WEB server v LAN

3.3.2015 6:54 / MaReK Olšavský
Recenze + instalace

Více ...

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