Kterak nakreslit modrý obdélník... - 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

Kterak nakreslit modrý obdélník...

24. října 2006, 00.00 | V minulém dílu našeho volného seriálu o programování ve vývojovém prostředí Cocoa jsme se pustili do implementace vlastních podtříd NSView; popsali jsme si základní strukturu a principy, a slíbili jsme si, že se dnes trochu blíže podíváme na hlavní a primární vlastnost "views" – totiž vykreslení jejich obsahu.

V minulém dílu našeho volného seriálu o programování ve vývojovém prostředí Cocoa jsme se pustili do implementace vlastních podtříd NSView; popsali jsme si základní strukturu a principy, a slíbili jsme si, že se dnes trochu blíže podíváme na hlavní a primární vlastnost "views" – totiž vykreslení jejich obsahu.

Metoda drawRect:

Už minule jsme si řekli, že základem vlastního kreslení je metoda drawRect:, a že základní princip funguje takto: je-li zapotřebí nějaké "view" překreslit, toto "view"

  • nejprve nastaví souřadnou soustavu tak, aby odpovídala jeho atributu "bounds" – tedy jeho vlastním souřadnicím, jež mohou být oproti ostatním "views" transformované –, a pak pošle samo sobě zprávu drawRect:;
  • pak view postupně předá požadavek na překreslení všem svým podřízeným "views", jež udělají totéž.

Je tedy zřejmé, že vlastní vykreslení obsahu "view" je právě obsahem metody drawRect:. Dnes si toho o ní řekneme malinko více: je deklarována takto:

-(void)drawRect:(NSRect)rect;

přičemž argument rect označuje obdélník, jehož obsah je zapotřebí překreslit. Programátor toho může využít pro optimalizaci, a přeskočit jakékoli kreslicí příkazy, jejichž efekt by se projevil pouze mimo tento obdélník.

Naopak ale není v žádném případě povinné se na daný obdélník omezit! Každé "view" standardně před voláním metody drawRect: nastaví "clipping" – tedy omezení prostoru, do nějž lze kreslit – právě na ten obdélník, jenž pak předá metodě drawRect: jako její atribut. Jinými slovy, programátor si může dovolit argument zcela ignorovat, a kreslit kamkoli cokoli; framework se postará o to, aby byl vykreslen pouze zadaný obdélník.

Základy práce s barvami

Dříve, než si ukážeme nějaké příklady implementace metody drawRect:, se musíme podívat na aspoň nejzákladnější příkazy pro nastavení atributů kreslení. Později si ukážeme, že takovýchto atributů je řada a k většině z nich máme přístup prostřednictvím třídy NSGraphicsContext; prozatím nám však stačí to nejjednodušší – nastavení požadované barvy.

Na to potřebujeme dva kroky: nejprve musíme potřebnou barvu – v prostředí Cocoa tedy objekt třídy NSColor – nalézt; pak musíme vědět, kterak grafickému subsystému dát na vědomí, že právě tuto barvu chceme používat nadále pro kreslení.

My si nejprve ukážeme ten druhý krok, protože je jednodušší: stačí libovolné barvě (instanci třídy NSColor) poslat standardní zprávu set. Od té chvíle, dokud nepošleme zprávu set jiné barvě, nebo dokud nepoužijeme jinou službu pro změnu atributů grafického subsystému, se bude pro kreslení používat právě tato barva:

NSColor *color=....;
[color set]; // od této chvíle kreslíme barvou "color"

A jak barvu získat? Nejjednodušší jsou třídní metody typu whiteColor, blackColor, blueColor a podobně, jež nabízejí přístup k základním, nejčastěji užívaným barvám – chceme-li kreslit třeba zeleně, stačí tedy provést příkaz

[[NSColor greenColor] set];

Seznam všech takovýchto metod nalezneme v dokumentaci třídy NSColor.

Kromě toho můžeme požadovanou barvu určit také prostřednictvím jejích složek. Máme k dispozici metody, využívající různé barevné prostory (zájemci je opět všechny naleznou v dokumentaci třídy NSColor); nejběžnější však rozhodně je barevný prostor RGB, a právě na něm si ukážeme příklad: odpovídající služba se jmenuje colorWithCalibratedRed:green:blue:alpha::

NSColor *color=[NSColor colorWithCalibratedRed:1 green:0 blue:0 alpha:1];
[color set]; // od této chvíle kreslíme červeně

Jednotlivé barevné složky mohou nabývat hodnot z intervalu 0-1; chceme-li právě poloviční intensitu, použijeme hodnotu 0.5. Designéři webových stránek jsou zvyklí na daleko hrubší paletu, určenou celočíselnými hodnotami z intervalu 0-255; je zřejmé, že dostaneme-li popis barvy v této podobě, snadno ji převedeme na naši pomocí dělení:

[NSColor colorWithCalibratedRed:r/255. green:g/255. blue:b/255. alpha:1];

Samostatný odstavec je vhodné věnovat složce alfa: ta vyjadřuje průhlednost (lépe řečeno neprůhlednost; alfa určuje míru, v níž daná barva odráží světlo). Mac OS X totiž plně a bez omezení dokáže pracovat s průhlednými (či spíše průsvitnými) barvami: použijeme-li barvu se složkou alfa rovnou 0.5, barva bude poloprůhledná – z 50 % tedy bude vidět to, co je pod ní. Použili-li bychom barvu s hodnotu alfa rovnou nule, vůbec bychom ji neviděli.

Nejjednodušší kreslení

Nyní se již můžeme podívat na ty nejzákladnější služby pro vlastní kreslení. Základem je rozhodně vykreslení obdélníku; k tomu Mac OS X nabízí několik možností, z nichž nejsnazší a nejjednodušší je služba NSRectFill. Dejme tomu, že chceme mít "view", jež je celé jednolitě modré – pak můžeme jeho metodu drawRect: implementovat takto:

-(void)drawRect:(NSRect)rect {
  [[NSColor blueColor] set];
  NSRectFill([self bounds]);
}

Výše uvedená implementace je zcela korektní a bude fungovat správně; je však zbytečně neefektivní: proč vybarvovat zbytečně kompletně celé pozadí našeho "view", pokud víme, že stačí překreslit pouze obdélník rect? Přesně stejně funkční, avšak o něco efektivnější implementace by mohla vypadat takto:

-(void)drawRect:(NSRect)rect {
  [[NSColor blueColor] set];
  NSRectFill(rect);
}

Je třeba ovšem zdůraznit, že v naprosté většině případů bude rozdíl zcela neměřitelný a nepodstatný, uvádíme oba příklady pouze pro lepší pochopení :)

Nadto je prvý přístup obvykle pohodlnější – to proto, že (ponecháme-li stranou jednolité pozadí celého "view") obvykle kreslíme ve vztahu k celé souřadné soustavě "view", tedy bounds, a nikoli pouze k právě překreslovanému obdélníku. Představme si, že chceme vykreslit jednoduché "view", vypadající nějak takto:

Je zřejmé, že toho můžeme docílit kupříkladu takto – využijeme-li standardních funkcí NSWidth a NSHeight, jejichž význam je zřejmý, a standardní funkce NSInsetRect, jež vygeneruje nový obdélník, na každé straně zúžený o hodnotu druhého a snížený o hodnotu třetího argumentu (tyto funkce bychom mohli přesnadno implementovat sami; využití standardních funkcí je však o něco málo efektivnější, a mnohem čitelnější :))

-(void)drawRect:(NSRect)rect {
  NSRect rr=[self bounds];
  [[NSColor blueColor] set];
  NSRectFill(rr);
  rr=NSInsetRect(rr,NSWidth(rr)/4,NSHeight(rr)/4);
  [[NSColor whiteColor] set];
  NSRectFill(rr);
}

Zde bychom již rect použít nemohli (přesněji řečeno, mohli, ale pouze v prvém příkazu NSRectFill, nikoli již ve druhém) – jinak bychom dostali zcela nesmyslný výsledek, v závislosti na v podstatě náhodné překreslované oblasti by se nám mohl bílý obdélník přemísťovat takřka "kamkoli".

Je vše zatím zřejmé? Ano-li, výborně! Ne-li, napište do diskuse... příště budeme pokračovat :)

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  

 » Rubriky  » Počítače  

Poslat článek

Nyní máte možnost poslat odkaz článku svým přátelům:

Váš e-mail:

(Není povinný)

E-mail adresáta:

Odkaz článku:

Vzkaz:

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: