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
Input Management
20. listopadu 2006, 00.00 | V minulém dílu našeho seriálu, věnovaného programování ve vývojovém prostředí Cocoa, jsme si ukázali, kterak užívat základních služeb třídy NSView (přesněji řečeno, její nadtřídy NSResponder; vzhledem k tomu však, že nyní se učíme sestavovat vlastní views, není zapotřebí to rozlišovat) pro zpracování událostí, přišedších od klávesnice.
V minulém dílu našeho seriálu, věnovaného programování ve vývojovém prostředí Cocoa, jsme si ukázali, kterak užívat základních služeb třídy NSView (přesněji řečeno, její nadtřídy NSResponder; vzhledem k tomu však, že nyní se učíme sestavovat vlastní views, není zapotřebí to rozlišovat) pro zpracování událostí, přišedších od klávesnice.
Naučili jsme se zkonfigurovat view tak, aby se mohlo stát tzv. first responderem a dostávalo tedy standardní zprávy keyDown:; zároveň jsme si také ale řekli, že ve většině případů je přímé využití zprávy keyDown: nepohodlné, a je daleko lepší využít vyšší úroveň služeb Cocoa pro zpracování vstupních dat, tzv. "input management". Jeho základům se právě budeme věnovat dnes.
Interpretace kláves
V zásadě se jedná o to, že si ponecháme stranou "ryze příkazové" kombinace kláves s přepínačem Command – ty se ostatně zpracovávají jinou cestou, již si popíšeme později, a v rámci zprávy keyDown: je vůbec nedostaneme – z klávesnice můžeme dostávat vstup, který se dělí do řady různých kategorií:
- běžné znaky – písmena apod. – se prostě vloží do textu;
- klávesy typu "delete" či "doplnění textu" mají trochu jiné postavení: sice text modifikují, avšak jedná se spíše o příkazy nežli o "vkládání textu" v pravém smyslu slova;
- šipky nebo klávesy "page up"/"page down" dokonce ani nemění obsah dokumentu.
Nadto je v mnoha případech žádoucí, aby uživatel mohl konkrétní funkci jednotlivých kláves volně definovat; v Mac OS X tomu tak skutečně je, a slouží k tomu soubory "KeyBinding.dict".
O všechny tyto věci (a řadu dalších) se stará knihovní vrstva zvaná "input management". Nebudeme si nyní podrobně popisovat, jaké služby obsahuje a jak přesně fungují; naučíme se ji pouze využívat v našich aplikacích.
Služba interpretKeyEvents:
Z tohoto pohledu prostého použití služeb input managementu máme vlastně jediný "vstupní bod" do jeho systému: tím je standardní metoda interpretKeyEvents:, jejímž argumentem je pole událostí (instancí třídy NSEvent). Služba všechny zadané události zpracuje, vezme korektně v úvahu nastavení přepínačů a další atributy, převede stisknuté klávesy na vložení textu či příkazy, o nichž jsme hovořili v minulém odstavci – a o nich informuje view prostřednictvím řady speciálních "akčních" zpráv.
Tak kupříkladu pro vložení textu dostane view zprávu insertText:; jejímž argumentem je NSString obsahující patřičný textový řetězec. Pro posun o jeden znak doleva – typicky tedy po stisknutí šipky vlevo, pokud zároveň nebyly drženy žádné speciální přepínače, a pokud není tato akce uživatelsky předefinovaná (o to vše se starají knihovní služby input managementu) – dostane view zprávu modeLeft:; podobně je tomu s ostatními příkazy. Možných zpráv, jež input management může views posílat, je řada a všechny standardní (systém je dostatečně flexibilní na to, abychom prostřednictvím "key bindings" mohli definovat i zprávy vlastní) můžeme nalézt ve standardní dokumentaci třídy NSResponder. Zde si vyjmenujeme pouze několik nejběžnějších a nejčastěji využívaných:
- cancelOperation: – zrušení právě probíhající operace, standardně odpovídá klávese "esc" či kombinaci "Command-.";
- deleteBackward: – smazání znaku před kursorem, standardně odpovídá klávese "Backspace";
- deleteForward: – smazání znaku za kursorem, standardně odpovídá klávese "Delete";
- insertTab: – standardně odpovídá stisknutí klávesy "Tab";
- insertNewline: – standardně odpovídá stisknutí klávesy "Enter";
- insertText: – o této zprávě jsme se již zmiňovali, jejím prostřednictvím systém input managementu předává view "obyčejné" znaky pro vložení do textu. Jsou uvedeny v objektu třídy NSString, jenž je argumentem zprávy;
- moveLeft:, moveUp:, moveDown: a moveRight: – přemísťování kursoru v textu, standardně odpovídá kursorovým šipkám;
- pageUp: a pageDown: – přechod na minulou či příští stránku, standardně odpovídá stejnojmenným klávesám.
Jednoduchý výběr grafických prvků
Pojďme na chvilku zanechat teoretického povídání a trochu si zaprogramujeme: doplníme do naší grafické aplikace jednoduchou možnost výběru grafických prvků.
Nejprve samozřejmě implementujeme metodu keyDown: tak, abychom z ní spustili služby input managementu:
-(void)keyDown:(NSEvent*)event { [self interpretKeyEvents: [NSArray arrayWithObject:event]]; }
Pro vlastní výběr prvků samozřejmě použijeme standardní služby moveLeft: a moveRight:; nejprve si však musíme připravit proměnnou, v níž budeme udržovat index aktuálně zvoleného prvku:
@interface View:NSView { // instances of NSBezierPath: NSMutableArray *lines; // selected, >[lines count] if none: unsigned selection; }
Pro vlastní označování využijeme – abychom si ušetřili nějaké ify – přetékání a podtékání hodnot v proměnné typu unsigned: odečteme-li v takové proměnné jedničku od nuly, můžeme se spolehnout, že dostaneme "hodně vysoké číslo". Následující implementace tedy bude postupně procházet grafické prvky v obou směrech, přičemž po posledním z nich jednou neoznačí nic, a pak začne opět dokola:
-(void)moveLeft:sender { if (selection-->[lines count]) selection=[lines count]-1; [self setNeedsDisplay:YES]; } -(void)moveRight:sender { if (++selection>[lines count]) selection=0; [self setNeedsDisplay:YES]; }
Samozřejmě, nesmíme zapomenout na inicializaci proměnné na "nic není označeno" po každém vložení nového grafického prvku:
-(void)mouseDown:(NSEvent*)evt { if ([evt modifierFlags]&NSShiftKeyMask) [self setNeedsDisplay:YES]; else { NSBezierPath *bp=[NSBezierPath bezierPath]; [bp moveToPoint: [self convertPoint: [evt locationInWindow] fromView:nil]]; [lines addObject:bp]; selection=1e6; // surely >[lines count] } }
a nakonec se postaráme o kreslení. Možností bychom měli řadu, prozatím však využijeme té nejjednodušší: prostě označený grafický prvek vykreslíme jinou barvou:
-(void)drawRect:(NSRect)rect { [[NSColor whiteColor] set]; NSRectFill(rect); unsigned n=0; for (id o,en=[lines objectEnumerator];o=[en nextObject];) { [n++==selection? [NSColor greenColor]:[NSColor blueColor] set]; [o stroke]; } ... // dále je vše při starém }
"Alerty" v Cocoa
Nakonec ještě implementujeme mazání označeného prvku – samozřejmě, nic jednoduššího, stačí použít standardní metodu deleteBackward:. Zároveň si ale ukážeme jednu věc, jež sice s views přímo nesouvisí, avšak je velmi důležitá – totiž správný způsob, kterak v Cocoa zobrazovat "alerty", informační či dotazové panely – zde jeden takový budeme potřebovat pro otázku, zda uživatel skutečně chce smazat všechny grafické objekty, pokud nebyl žádný označen.
V Cocoa je považováno za nesprávné v takovémto případě zablokovat celou aplikaci modálním panelem; namísto toho je korektním řešením zobrazit "sheet", vázaný pouze na jediné konkrétní okno. To ovšem samozřejmě znamená, že musíme zobrazení "alertu" a zpracování jeho výsledku oddělit do dvou samostatných metod (aby mezi jejich provedením mohla aplikace bez obtíží dělat jiné věci) – asi takto:
-(void)alertClosed:(NSWindow*)sheet result:(int)result { if (result==NSAlertDefaultReturn) { [lines removeAllObjects]; [self setNeedsDisplay:YES]; } } -(void)deleteBackward:sender { if ([lines count]==0) return; if (selection<[lines count]) { [lines removeObjectAtIndex:selection]; [self setNeedsDisplay:YES]; } else NSBeginAlertSheet( @"Delete all graphics?", // title @"Yes, delete",@"No",nil, // buttons [self window], // window to which it belongs self, // this object will get ... @selector(alertClosed:result:), // ...this message NULL,NULL, // extra possibilities, unused @"Do you really want to delete %d graphics objects?", [lines count]); // alert body, as in NSLog }
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