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:
Software
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):
- Nastal čas na kakao...
- Tak nejdřív kakao ochutnáme...
- Programovací jazyk C: velmi, velmi stručně
- Objective C: to si vysvětlíme podrobněji
- Co jsme si o Objective C ještě neřekli...
- Nastal čas na kakao - Vznik a zánik objektů
- Nastal čas na kakao - Kopírování objektů
- Nastal čas na kakao - Skryté podtřídy
- Nastal čas na kakao - Základní služby objektů
- Nastal čas na kakao - Jak správně psát v Objective C
- Nastal čas na kakao - Jak správně importovat
- Nastal čas na kakao - Podtřídy, delegáti, vkládání, jak se to rýmuje?
- Nastal čas na kakao - Využití kategorií namísto dědičnosti
- Nastal čas na kakao - Vkládání objektů a přesměrování zpráv
- Nastal čas na kakao - Inicializace a rušení objektů
- Nastal čas na kakao - Metody initWith... a designovaný inicializátor
- Nastal čas na kakao - Inicializace: tipy a triky
- Nastal čas na kakao - Accesory: přístup k proměnným instancí
- Nastal čas na kakao - Šedá je teorie, zelený je strom života...
- Nastal čas na kakao - Více o XCode: inspektory
- Nastal čas na kakao - Aplikace RSS2: datový model
- Nastal čas na kakao - Aplikace RSS: implementace datového modelu
- Nastal čas na kakao - Aplikace RSS: parsování XML
- Nastal čas na kakao - Interface Builder a uživatelské rozhraní
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Interface Builder: atributy objektů
- Nastal čas na kakao - Druhý kontrolér a dokončení aplikace
- Nastal čas na kakao - Drobná vylepšení a zdokonalení...
- Nastal čas na kakao - Ladění
- Nastal čas na kakao - Třídy Foundation Kitu
- Nastal čas na kakao - Třídy Foundation Kitu (2)
- Nastal čas na kakao - Textové řetězce: NS(Mutable)String
- Nastal čas na kakao - Čísla, binární data a další...
- Nastal čas na kakao - Archivace objektů
- Nastal čas na kakao - Trocha magie, aneb distribuované objekty
- Nastal čas na kakao - Málem bychom zapomněli: NSAutoreleasePool
- Nastal čas na kakao - Zpracování výjimek: NSException
- Nastal čas na kakao - NSInvocation a černá magie
- Nastal čas na kakao - Kakao v Tygrovi
- Nastal čas na kakao - Notifikace: nepřímé předávání zpráv
- Nastal čas na kakao - NSUserDefaults
- Nastal čas na kakao - Co nového ve Foundation Kitu
- Nastal čas na kakao – s Intelem, s Intelem, jedeme do...
- Co nového v Xcode
- Začínáme s AppKitem
- Jak MVC v Kakau vypadá doopravdy?
- Jak MVC v Kakau vypadá doopravdy: dokončení
- Přehled tříd AppKitu
- Nastal čas na kakao - Přehled tříd AppKitu 2
- Přehled tříd AppKitu 3: zbývající třídy GUI
- Přehled tříd AppKitu 4: textový systém
- Nastal čas na kakao - Přehled tříd AppKitu 5: hlavně grafika
- Přehled tříd AppKitu 6: dokumentový systém
- Přehled tříd AppKitu 7: dokončení
- Pojmenované vlastnosti objektů
- Pojmenované vlastnosti objektů: implementace
- Pojmenované vlastnosti objektů: relace 1:N
- Pojmenované vlastnosti objektů: řazení jmen a agregační funkce
- Sledování změn objektů
- Sledování změn objektů – ukázka
- Sledování změn objektů – zdrojový kód
- Sledování změn objektů: kód modelu
- Sledování změn objektů: přímý přístup
- Kontroléry a vazby
- Vázání vazeb
- Další vazby s jednoduchým kontrolérem
- Implementace a použití převodu hodnot
- Validace hodnot
- Validace a chyby, a jedna hezká vazba...
- Práce s polem objektů
- Základní vazby NSArrayControlleru
- Převodníky, přepínače, placeholdery
- Mírná vylepšení v mezích zákona
- Objective C 2.0 - novinky z Leoparda
- NSTreeController
- Programování v Cocoa - Pár tipů a triků
- Programování v Cocoa - Základy kreslení
- Kterak nakreslit modrý obdélník...
- Další služby pro kreslení
- Obrázky a písmenka...
- Události a myš
- Lepší práce s myší
- Události klávesnice
- Input Management
- Příkazy a schránka
- Další události
- Táhni a padni
- Byli jsme na tahu; nyní padneme.
- Zvolme si, jak vhodit
- Drobnosti a chybičky
- Speciální případy tahání či házení
- Kterak táhnout něco, co neexistuje?
- Jak na sítě...
- NSURLConnection
- Safari za minutu
- Služby WebKitu
- Kakao v Leopardu
- Druhé Objective C
- Druhé Objective C: různé drobnosti
- Druhé Objective C: kategorie a protokoly
- Druhé Objective C: nový příkaz cyklu
- Druhé Objective C: atributy a accesory
- Druhé Objective C: atributy a accesory
- 64 je dvakrát 32
- Ubicumque dulce est, ibi et acidum invenies...
- Irbis: že prý žádné novinky?
- Blok sem, blok tam, nám už je to všechno jasné...
- Bloky jsou i v AppKitu
- Irbis a Foundation Kit
- Kde jsou má data?
- Kde jsou má data? V NSCache!
- Soubor, jméno, URL, jak se to rýmuje...
- Další podpora NSURL
- Zabíjení!
- A máme tady i...OS!
- Systémové prvky GUI
- Programování pro iOS 1. díl - Rozdíly mezi "i" a "Mac"
- Programování pro iOS - 2. Začínáme programovat
- Programování pro iOS - 3. základní ovladače a propojení GUI s kódem
- Programování pro iOS - 4. Varovná hlášení
- Programování pro iOS - 5. Rámce a jejich řídicí objekty
- Programování pro iOS - 6. Ukládání dat
- Programování pro iOS - 7. Správa paměti a starý restík
- Programování pro iOS - 8. Dokončení aplikace
- Programování pro iOS - 9. Jak dostat aplikaci do iPhone
- Programování pro iOS - 10. Instalace aplikace do cizího iPhone
- Programování pro iOS - 11. Jak dostat aplikaci do libovolného iPhone
- Programování pro iOS - 12. Touching!
- Programování pro iOS - 13. Kreslíme na iPhone
- Programování pro iOS - 14. Udělejme gesto
- Programování pro iOS - 15. Další gesta
- Programování pro iOS - 16. Více prstů, více zábavy
- Programování pro iOS - 17. Podpora standardních gest
- Programování pro iOS - 18. Recognizery v iOS
- Programování pro iOS - 19. Další standardní recognizery
- Programování pro iOS - 20. Co nového v iOSu
- Programování pro iOS - 21. "Multitasking"
- Programování pro iOS - 22. Nulla est honesta avaritia nisi temporis
- Programování pro iOS - 23. Jak se aktivovat, jsme-li v pozadí
- Programování pro iOS - 24. Zbývající drobnosti
- Programování pro iOS - 25. Řídicí objekty rámců
- Programování pro iOS - 26. Jak se dělá UIViewController
- Programování pro iOS - 27. Kde vzít rámce
- Programování pro iOS - 28. Základní služby
- Programování pro iOS - 29. Práce s rámci
- Programování pro iOS - 30. Rotace zařízení
- Programování pro iOS - 31. Správa paměti v rámcích
- Programování pro iOS - 32. Řídicí objekt pro tabulky
- Programování pro iOS - 33. Řídicí objekt pro strom
- Programování pro iOS - 33. Více o UINavigationControlleru
- Programování pro iOS - 35. Ještě jednou UINavigationController
- Programování pro iOS - 36. Po navigátoru taby
- Programování pro iOS - 37. Více o UITabBarControlleru
- Programování pro iOS - 38. Dokončení UITabBarControlleru
- Programování pro iOS - 39. UIPopoverController
- Programování pro iOS - 40. Další triky UIPopoverControlleru
- Programování pro iOS - 41. Zbývající služby UIPopoverControlleru
- Programování pro iOS - 42. UISplitViewController
- Programujeme v
iTunesXcode 4 - Programování pro iOS - 44. Předvolby Xcode 4
- Programování pro iOS - 45. Práce v Xcode 4
- Xcode 4: projekt a cíle
- Xcode 4: práce s cíli
- Xcode 4: Build Settings
- Xcode 4: Build Phases
- Xcode4: Build Phases podruhé
- Xcode 4: Co jsou to Build Rules?
- Xcode4: taje editoru
- Xcode4: automatické doplňování v editoru
- XIBy chyby
- Více o XIBech
- Editor XIBů
- Inspektory pro XIBy
- Vazby mezi objekty v XIBech
- Vazby mezi objekty v kódu
- Paletky Xcode pro XIBy
- Xcode 4: levý sloupec
- Xcode 4: okno Organizer
- Xcode 4: okno Organizer, část druhá
- Xcode 4: co je to Workspace?
- Xcode 4: základy schémat
- Xcode 4: akční schémata