Události klávesnice - MujMAC.cz - Apple, Mac OS X, Apple iPod

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:

Soutěž

Sponzorem soutěže je:

IDIF

 

Kde se narodil známý fotograf František Drtikol?

V dnešní soutěži hrajeme o:

Seriály

Více seriálů



Informace

Události klávesnice

17. listopadu 2006, 00.00 | V současné době se v našem seriálu o programování ve vývojovém prostředí Cocoa učíme sestavovat vlastní views. Dnes se podíváme na to, jak zpracovávat události vytvářené druhým nejdůležitějším vstupním zařízením, klávesnicí.

V současné době se v našem seriálu o programování ve vývojovém prostředí Cocoa učíme sestavovat vlastní views. Nejprve jsme si ukázali základy kreslení jejich obsahu prostřednictvím standardní metody drawRect:, a nyní se zabýváme podporou zpracování událostí ("events"), generovaných vstupními zařízeními. V několika předcházejících dílech jsme se naučili zpracovávat základní události, generované prostřednictvím myši – především stisknutí jejího tlačítka a tažení; nyní se podíváme na to, jak zpracovávat události vytvářené druhým nejdůležitějším vstupním zařízením, klávesnicí.

Zprávy keyDown: a keyUp:

V principu je tomu s událostmi generovanými stisknem kláves stejně, jako s událostmi myši: framework je nějak získá, a pro každé stisknutí klávesy vygeneruje a pošle odpovídající zprávu keyDown:, jejímž argumentem je opět instance třídy NSEvent, obsahující podrobné informace o tom, která klávesa byla stisknuta, jaké byly v tu chvíli stisknuté přepínače a podobně. Po uvolnění klávesy pak obdobně pošle zprávu keyUp:.

Můžeme tedy hned do našeho projektu prajednoduché kreslicí aplikace, který jsme vytvořili v předminulém a přepracovali a vylepšili v minulém dílu, přidat – jen tak jednoduše pro otestování – třeba takovouto metodu:

-(void)keyDown:(NSEvent*)event {
  NSLog(@"keyboard: \"%@\"",[event characters]);
}

Můžeme aplikaci zbuildovat, spustit, a... mačkat klávesy jak dlouho chceme, v logu se neobjeví zhola nic! Jak je to možné? Inu, zapomněli jsme se postarat o nastavení responderů.

Kdo je First Responder a proč se nám plete do zpracování kláves?

Musíme si uvědomit, že přidělování událostí vytvářených prostřednictvím klávesnice není zdaleka tak jednoduché, jako přidělování událostí generovaných pomocí myši. U myši prostě knihovní kód našel okno, nad nímž se kursor myši ve chvíli události nalézá, v tomto okně podobně vyhledal v hiearchické struktuře "nejnižší" view z těch, nad nimiž myš právě je – a je to, právě tomuto view se zpráva mouseDown: pošle.

V případě klávesnice to tak prosté není: zajisté, systém si udržuje informaci o tom, které okno je právě aktivní ("key window", "focused window"), a zprávu keyDown: tedy bude zapotřebí poslat některému view právě v tomto okně. Ale kterému? Některá unixová grafická uživatelská rozhraní i zde volí právě to view nad nímž je zrovna myš; z hlediska uživatele je to ale neobyčejně nepraktické (představme si, že v naší grafické aplikaci budeme mít textové pole pro zadávání souřadnic – pak bychom určitě chtěli, aby šlo ovládat a měnit souřadnice i v době, kdy je myš nad hlavní "kreslicí" oblastí). Z ergonomického hlediska je třeba zvolit jiné řešení.

V Cocoa je tímto řešením tzv. first responder: knihovny pro každé okno udržují informaci o tom, které view je právě "aktivní"; toto view se nazývá "first responder", a události klávesnice jsou posílány právě jemu. Aby nám aplikace fungovala jak má, musíme se postarat o dvě věci:

  • musíme informovat systém o tom, že naše view je vůbec "ochotné a schopné" události z klávesnice přijímat a zpracovávat;
  • také je zapotřebí informovat okno o tom, že po spuštění (resp. po zobrazení tohoto okna, což je v případě naší jednoduché aplikace totéž) se má nastavit jako first responder právě naše view a žádné jiné.

Metoda acceptsFirstResponder:

Pro splnění prvé úlohy je třeba implementovat standardní metodu acceptsFirstResponder: a vrátit z ní hodnotu YES – stačí k tomu tři řádky zdrojového kódu, asi takto:

-(BOOL)acceptsFirstResponder {
  return YES;
}

Možná stojí za to se na chvilku zdržet a uvědomit si, proč vlastně takové "zbytečnosti" jako metoda acceptsFirstResponder: existují a "otravují nám život": vždyť přece knihovny Cocoa by se mohly prostě "podívat", zda náš kód obsahuje implementaci metody keyDown:, v kladném případě view jako first responder použít, a v záporném nikoli, n'est ce pas?

Inu, nikoli – nebylo by to dostatečně flexibilní. Připomeňme si dynamickou podstatu jazyka Objective C, jíž jsme se podrobně zabývali v začátcích našeho seriálu; naše view by klidně mohlo zprávy jen přesměrovávat nějakému kontroléru a samo je neimplementovat. V takovém případě by se jistě "chtělo" stát first responderem i bez vlastní implementace metody keyDown:.

Na stranu druhou – a to je dokonce mnohem pravděpodobnější – se může stát, že nějaké view sice metodu keyDown: implementuje, avšak právě teď klávesy přijímat nehodlá, z jakéhokoli důvodu, daného jeho vnitřním stavem (příkladem může být třeba textové pole, jež je momentálně v režimu "disabled").

Outlet initialFirstResponder

Druhý úkol – informovat okno o tom, kterému z jeho views má předat roli first respondera po zobrazení – je ještě snazší, a programovat vůbec nemusíme; kompletně jej splníme v aplikaci Interface Builder. Otevřeme v ní opět NIB obsahující grafické uživatelské rozhraní aplikace, a pomocí již dávno známého "tahání drátů" s přepínačem "control" uložíme odkaz na naše view do "outletu" okna jménem "initialFirstResponder":

To je vše: nyní můžeme aplikaci přebuildovat, a v logu uvidíme, že nyní nám již knihovny Cocoa prostřednictvím zprávy keyDown: korektně hlásí každou stisknutou klávesu.

Implementace zprávy keyDown

Mohli bychom se tedy pustit do implementace, založené patrně na spoustě ifů, nějak zhruba na tomto principu:

-(void)keyDown:(NSEvent*)event {
    if ([[event characters] isEqualToString:@"c"]) { // clear all lines
        [lines removeAllObjects];
        [self setNeedsDisplay:YES];
    }
}

Nebylo by to ovšem nijak zvlášť přehledné ani pohodlné, museli bychom hledat, jakými znaky jsou vlastně representovány speciální klávesy jako třeba šipky (ono by jistě bylo lepší ve výše uvedeném příkladu použít klávesu "delete" než "c", ale co vlastně v takovém případě bude v [event characters]?), a tak dále.

Cocoa ovšem nabízí bohaté standardní služby pro zpracování kláves na vyšší úrovni; ty si již ale ukážeme až v příštím dílu.

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » Informace  

 » Rubriky  » Agregator  

 » Rubriky  » Tipy a Triky  

 » Rubriky  » Začínáme s  

 » Rubriky  » Software  

 

 

 

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: