Události a myš - 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ů



Software

Události a myš

8. listopadu 2006, 00.00 | V předcházejících pokračováních jsme se naučili implementovat metodu drawRect:, jejímž prostřednictvím definujeme to, jak view vypadá. Nyní se zaměříme na druhou stránku views – na jejich schopnost reagovat na nejrůznější události, generované prostřednictvím vstupních zařízení. Začneme tím nejjednodušším, myší.

V našem seriálu, věnovaném základům programování v prostředí Cocoa, se v posledních několika dílech zabýváme tím, kterak vytvářet vlastní views – objekty grafického uživatelského rozhraní, z nichž sestává vzhled a ovládání aplikace. Ačkoli standardně Cocoa obsahuje předlouhou řadu views vhodných pro spoustu případů – od nejjednodušších obdélníků NSBoxView až po komplikované struktury jako NSTableView či NSTextView –, většina složitějších aplikací se neobejde bez nějakého vlastního view, uzpůsobeného přesně potřebám konkrétní aplikace.

V předcházejících pokračováních jsme se naučili implementovat metodu drawRect:, jejímž prostřednictvím definujeme to, jak view vypadá. Nyní se zaměříme na druhou stránku views – na jejich schopnost reagovat na nejrůznější události, generované prostřednictvím vstupních zařízení. Začneme tím nejjednodušším, myší.

Co se vlastně dá s myší dělat?

Ačkoli myš je poměrně velmi jednoduché zařízení – obzvláště klasická myš Apple, jež má toliko jediné tlačítko a není vybavena žádným rollerem –, dokáže generovat řadu nejrůznějších událostí; mezi ně patří kupříkladu

  • klepnutí na dané místo;
  • poklepání nebo vícenásobné klepnutí na dané místo;
  • stisknutí a přidržení tlačítka myši – a jeho opětovné povolení;
  • tažení;
  • pouhá změna polohy myši bez stisknutí nějakého tlačítka;
  • vstup myši do vyhrazeného obdélníka nebo jeho opuštění...

Postupně si ukážeme základní principy toho, kterak můžeme tyto i další události v prostředí Cocoa obsloužit. Dnes ale začneme s tím nejjednodušším – stisknutí a uvolnění tlačítka.

NSResponder a NSEvent

Již dříve jsme se orientačně seznámili s třídou NSResponder a řekli jsme si, že právě na ní je založen celý model zpracování událostí v Cocoa. Jelikož třída NSView je dědicem třídy NSResponder, všechny její možnosti a služby jsou nám zde plně k dispozici.

Ačkoli Cocoa samozřejmě programátorům umožňuje přímé zpracování událostí – a my si samozřejmě později také ukážeme jak na to –, bylo by to příliš nepohodlné; namísto toho necháme celou skupinu standardních tříd a služby, založené na třídě NSResponder, aby většinu práce udělaly za nás. V takovém případě se nemusíme takřka o nic starat: aplikace se nějak dozví od Window Serveru, že uživatel stiskl tlačítko myši, a nějak zjistí, nad kterým oknem to bylo; nějak najde také patřičné view – a pošle mu standardní zprávu mouseDown:. Nám tedy jen stačí implementovat tuto zprávu a v ní udělat cokoli, co je zapotřebí. Podobně uvolnění tlačítka myši je indikováno zprávou mouseUp:.

Argumentem těchto zpráv je instance třídy NSEvent. To je universální třída, jež dokáže representovat libovolnou událost a všechny její atributy; jejím prostřednictvím kupříkladu můžeme zjistit souřadnice, na nichž byl kursor myši ve chvíli, kdy uživatel stiskl tlačítko.

Jednoduchá aplikace

Pojďme si sestavit zcela triviální kreslicí aplikaci: nebude umět dohromady nic, jen v jejím view budeme moci tažením myši z místa na místo nakreslit čáru (pro co nejjednodušší kód dokonce ani nebudeme zobrazovat čáru průběžně při kreslení – teprve až po uvolnění tlačítka). Asi nějak takto:

Vytvořit nový projekt již dokážeme dávno; otevřeme jeho "NIB", do okna vhodíme z palety "Cocoa Containers" objekt "Custom View". Pak v projektu vytvoříme nový soubor "View.m" (a zároveň "View.h") jako dědice třídy NSView – vývojové prostředí XCode nám tuto možnost nabídne jako "Objective C NSView subclass".

Pak hlavičkový soubor "View.h" vhodíme myší do okna Interface Builderu – tak se Interface Builder dozví, že existuje nějaká třída View – a pomocí inspektoru "Custom Class" určíme, že ono "Custom View", jež jsme před chvilkou vytvořili, má representovat právě objekt třídy "View". To vše již dávno umíme, tak by to neměl být žádný problém.

Properties a kreslení

Vlastní proměnné – properties – naší třídy View budou neobyčejně jednoduché: bude zde jen jedno pole (do nějž budeme ukládat nakreslené čáry), a jedna pomocná proměnná typu NSPoint. Té využijeme při kreslení – při stisknutí myši si do ní uložíme momentální polohu kursoru, abychom mohli při jejím uvolnění nakreslit čáru:

@interface View:NSView {
    NSMutableArray *lines;
    NSPoint start;
}
@end

Také kreslení bude velice jednoduché, a nebudeme na ně ani zdaleka potřebovat vše, co jsme se naučili v předcházejících dílech našeho seriálu: dejme tomu, že budeme čáry do pole lines ukládat jako dvojice bodů, oba dva kódované pomocí třídy NSValue (vzpomínáte si na ni ještě z našeho povídání o Foundation Kitu? Jedná se o pomocnou třídu, jež dokáže uložit hodnotu libovolného typu do standardního objektu) a uložené do vnořeného dvouprvkového pole. Kreslení by pak mohlo vypadat třeba takto:

-(void)drawRect:(NSRect)rect {
  [[NSColor whiteColor] set];
  NSRectFill(rect);
  [[NSColor blueColor] set];
  for (id o,en=[lines objectEnumerator];o=[en nextObject];)
    [NSBezierPath strokeLineFromPoint:
      [[o objectAtIndex:0] pointValue]
      toPoint:[[o objectAtIndex:1] pointValue]];
}

Nejprve vybarvíme bíle pozadí; pak nastavíme modrou, a projdeme postupně všechny objekty v poli lines. O každém předpokládáme, že je sám dvouprvkovým polem – přičemž oběma jeho prvkům můžeme poslat zprávu pointValue, a dostaneme hodnoty typu NSPoint.

Práce s myší

To nejdůležitější, vlastní práci s myší, jsme si nechali nakonec – jak hned ale uvidíme, je to opravdu velice jednoduché. Nejprve implementujeme metodu, jež se – jak jsme si vysvětlili výše – automaticky zavolá kdykoli nad naším view uživatel stiskne tlačítko myši:

-(void)mouseDown:(NSEvent*)evt {
    start=[self convertPoint:[evt locationInWindow] fromView:nil];
}

Její obsah je velmi jednoduchý – prostě uloží momentální pozici kursoru do proměnné start. Za zmínku stojí

  • to, že instance NSEvent vždy obsahuje pozici myši relativní vůči oknu (tedy nikoli view), a můžeme ji získat prostřednictvím standardní zprávy locationInWindow;
  • to, že každá instance třídy NSView dokáže libovolně převádět souřadnice mezi všemi views v témže okně. Chceme-li převést souřadnice, vyjádřené v souřadné soustavě nějakého view – třeba "x" – do našich, stačí použít zprávu convertPoint:pt fromView:x. Speciálním případem pak je, neurčíme-li zdrojové view (tedy použijeme-li na jeho místě hodnotu nil); pak se souřadnice převedou ze souřadné soustavy celého okna – což je přesně to, co nyní potřebujeme.

Pro úplnost je vhodné dodat, že standardní metody třídy NSView dokáží stejně dobře převádět nejen body, ale i ostatní geometrické objekty, a že je dokáží stejně dobře převádět z jiného view jako do něj. Kdybychom kupříkladu měli nějaký obdélník v naší souřadné soustavě, a chtěli bychom jej vyjádřit v souřadné soustavě nějakého view "x", použili bychom zprávu convertRect:r toView:x.

Zbývá již jen metoda mouseUp:, jež se zavolá po uvolnění tlačítka myši. V ní samozřejmě využijeme téže konverse souřadnic, a oba body převedeme na objekty třídy NSValue a uložíme je do našeho pole lines:

-(void)mouseUp:(NSEvent*)evt {
  if (!lines) lines=[NSMutableArray new];
  [lines addObject:
    [NSArray arrayWithObjects:
      [NSValue valueWithPoint:start],
      [NSValue valueWithPoint:
        [self convertPoint:[evt locationInWindow] fromView:nil]
      ],nil]];
  ...

Ještě však zbývá jedna drobnost: po změně obsahu pole lines musíme nějak zajistit, aby se obsah našeho view překreslil. Samozřejmě jej nebudeme kreslit přímo – jen informujeme framework o tom, že je zapotřebí, aby se obsah překreslil v nejbližší vhodný okamžik. K tomu slouží standardní metoda setNeedsDisplay:

  ...
  [self setNeedsDisplay:YES];
}

A to je již opravdu všechno: můžeme aplikaci zbuildovat, a vesele kreslit...

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  

Diskuse k článku

 

Vložit nový příspěvek   Sbalit příspěvky

 

Zatím nebyl uložen žádný příspěvek, buďte první.

 

 

Vložit nový příspěvek

Jméno:

Pohlaví:

,

E-mail:

Předmět:

Příspěvek:

 

Kontrola:

Do spodního pole opište z obrázku 5 znaků:

Kód pro ověření

 

 

 

 

 

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

Uživatelské jméno:

Heslo: