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

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ů

19.12.2014 7:20 /MaReK Olšavský
Předvánoční dárek pro databázaře vyšel v podobě PostgreSQL 9.4. O novinkách napsal český článek Pavel Stěhule. Opravy chyb a drobná vylepšení jsou standardem, podpora datového typu JSON je velkým skokem vpřed.
Přidat komentář

19.12.2014 7:20 /MaReK Olšavský
Zdá se, že by se Intel mohl přecijen uchytit; vedle ARM; v segmentu chytrých telefonů. Čínské Lenovo plánuje pro rok 2015 nasazení Intelovského Atomu v nových smrtphonech.
Přidat komentář

19.12.2014 7:20 /MaReK Olšavský
Jazzový zpěvačka/pianistka Dinah Washington propůjčila jméno CMS Wordpress 4.1, jehož nejvýraznější novinkou je mód pro „nerušené psaní“.
Přidat komentář

18.12.2014 7:00 /MaReK Olšavský
Porovnání FreeBSD a OpenBSD (delší článek) vyšlo na blogu Network Filter. Asi nikoho nepřekvapí, že nelze jednoznačně určit vítěze a jednoznačné doporučení „nasaďte XYZ“.
Přidat komentář

18.12.2014 7:00 /MaReK Olšavský
Snad již poslední novinkou o vydání distribuce Fedora 21 jsou verze pro 64 bitové mikroprocesory ARM (oznámení) a pro mikroprocesory Power (oznámení). Obě verze budou mít asi poměrně malou cílovou skupinu ve správcích serverů. BTW: OpenPOWER Foundation se rozrostla o Rackspace.
Přidat komentář

18.12.2014 7:00 /MaReK Olšavský
Vznik další distribuce často komentuji slovy „kdybyste měli pocit, že distribucí je málo“, ale podle dlouhodobého sledování stránek DistroWatch naopak počet distribucí klesá. Lze to vnímat jako pozitivní jev, kdy se vývojáři spojují, místo vytváření bezpočtu derivátů.
Přidat komentář

17.12.2014 7:19 /MaReK Olšavský
Martin Malý napsal článek pro (nás) pamětníky o počítačích za železnou oponou. Zatím zvládl podchytit stav pouze někdejšího Česko—Slovenska :-).
Přidat komentář

17.12.2014 7:19 /MaReK Olšavský
National Geographic je známý svými populárně naučnými TV stanicemi, nebo vydáváním časopisu. Jak používá svobodný software prozradil Shah Selbe.
Přidat komentář

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

> Poslední diskuze

16.12.2014 3:59 / Jaroslav Kelt Kuchera
Download Perl

11.12.2014 6:42 / MaReK Olšavský
Po instalaci

10.12.2014 19:26 / Vladimir VASIL
Re: Sanba

11.11.2014 14:24 / Libor Suchý
Nekonečný while cyklus

10.11.2014 19:09 / Libor Suchý
Re: tabulka - bitovy sucet

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