13th ottobre, 2008

Gestione NSView in Cocoa. Per: “progetto cresciamo insieme” [n.1] Parte 2

by Stefano Lodu
Secondo articolo per il "concorso : cresciamo insieme" n.1
Scritto da Alessandro - seconda parte
5. Interattività

16) A questo punto, iniziamo la parte interattiva. Cocoa dispone di una gran mole di funzioni per interagire con l’interfaccia grafica. Tra le più interessanti c’è senza dubbio l’interazione con tastiera e mouse: non solo è possibile intercettare il clic del mouse, il doppio clic o il trascinamento – che è indispensabile per il famoso drag-and-drop – ma è anche possibile interpretare un tasto premuto sulla tastiera, o un tasto rilasciato, il che ricorda molto da vicino la pressione e il rilascio di un dito sulla tastiera di un iPhone! Ovviamente, non sono le stesse librerie, ma il concetto è lo stesso: intercettare l’input dell’utente (in gergo si chiama: interrupt) per permettere al software di “reagire” di conseguenza.

Vedremo ora come intercettare la pressione dei tasti freccia: Su, Giù, Sinistra e Destra.

Per fare questo, si utilizza l’oggetto: NSEvent, che si occupa appunto della gestione degli eventi.

Affinché la nostra NSView AreaDiGioco.m possa riconoscere e quindi interpretare un evento, è tuttavia fondamentale aggiungere due piccole ma importanti funzioni: prima di tutto bisogna che la nostra AreaDiGioco diventi sensibile, poi che accetti un input o un evento: – (BOOL)becomeFirstResponder e – (BOOL)acceptsFirstResponder sono le funzioni che servono in questo caso.

Una volta aggiunte queste due piccole funzioni, si crea la funzione – (void)keyDown:(NSEvent *)theEvent vera e propria, che si occuperà di valutare ed elaborare il risultato dell’inpur da tastiera:

17) Adesso compilate il programma (Command+R) e provate a cliccare sui tasti freccia. Il risultato dovrebbe essere simile a questo:

18) Semplice e meraviglioso, non trovate? A questo punto, facciamo in modo che premendo uno dei tasti freccia succeda qualcosa di più interessante! Alla pressione di uno dei tasti freccia, vogliamo che il riquadro corrispondente lampeggi in color magenta per poi tornare al colore originario.

Per fare questo, dobbiamo creare due diverse funzioni: la prima colorerà di magenta l’area corrispondente al pulsante premuto; la seconda, si occuperà di ridisegnare l’intera area della nostra finestra una volta rilasciato il tasto. Ma vediamo nel dettaglio come fare:

usando il vecchio e sempre caro copia e incolla (universalmente noto come il miglior metodo per evitare errori di battitura!), assegno ad ogni tasto premuto un’area, e la passo alla prima funzione che vado a creare: – (void)flash:(NSBezierPath * )flash che si occuperà di colorare l’area di magenta.

- (void)flash:(NSBezierPath *)flash {

[self lockFocus];

[[NSColor magentaColor] set];

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.);

[[NSGraphicsContext currentContext] flushGraphics];

[self unlockFocus];

}

Questa funzione utilizza un piccolo trucco, che potete leggere nel codice: prima di tutto, blocca l’area visualizzata; in secondo luogo disegna gli eventuali cambiamenti sopraggiunti; infine aggiorna il disegno della nostra NSView AreaDiGioco e sblocca la NSView lasciandola libera di ricevere nuovi input.

Questa procedura, che comincia con l’istruzione: [self lockFocus] e prosegue con: [[NSGraphicsContext currentContext] flushGraphics] per terninare con: [self unlockFocus] è valida universalmente, quando si tratta di disegnare con una NSView, perciò conoscerla è molto utile.

Una volta creata questa prima funzione, passiamo alla seconda: la funzione – (void)keyUp:(NSEvent *)theEvent. Molto simile alla funzione keyDown, questa funzione si occupa semplicemente di ridisegnare lo schermo com’era all’inizio. Anche qui, l’utilizzo del principio che comincia con [self lockFocus] è fondamentale.

6. Ottimizzazione

19) Come avrete notato, alcune parti di codice sono ripetute più volte nel file AreaDiGioco.m: in diversi punti ho dovuto ripetere le dimensioni delle quattro zone colorate (verde, blu, giallo, rosso), creando non pochi problemi di lettura del codice e di mantenimento dello stesso. Certo, questo è un semplice tutorial che prevede solamente un paio di file, ma è buona prassi ottimizzare il codice sia per evitare possibili errori (scrivendo due volte la stessa cosa, siete davvero sicuri di averla scritta sempre uguale?) sia per facilitare il debug e la comprensione del codice stesso. Per ottimizzare il codice di questo esempio, è necessario accorgersi che le quattro zone da colorare sono oggetti a se stanti (non preoccupatevi, con un po’ di pratica di programmazione OOP lo noterete subito), per cui è meglio, in questo caso, definire una volta sola queste quattro aree o NSBezierPath nel file AreaDiGioco.h, e richiamarle quando serve.

20) In questa maniera, le quattro aree che andremo a colorare e ad evidenziare premendo i tasti freccia saranno sempre a disposizione senza alcun bisogno di dover essere definite con più o meno complicate assegnazioni di NSRect eccetera. Basterà definirle una volta per tutte all’avvio del programma, nella funzione – (id)initWithFrame:(NSRect )frame, e saranno sempre con noi durante tutto l’utilizzo dell’applicazione.

MI RACCOMANDO!! Ricordatevi di trattenere queste variabili, una volta dichiarate! Se omettere il comando [retain] dopo averle dichiarate in: (id)initWithFrame:(NSRect)frame, non ne avrete alcun beneficio: il programma andrà in crash!! Quindi ricordatevi di ritenete le variabili che dichiarate all’init, mi raccomando.

21) In questo modo, tutto il codice sarà più pulito e leggibile. Un programmatore esperto sarebbe partito direttamente da questa considerazione e non avrebbe sperimentato altre soluzioni: per lui sarebbe stato ovvio considerare le diverse parti colorate dell’interfaccia come entità separate. Anzi, probabilmente le avrebbe instanziate come NSSubViews, ma qui le cose si complicano, per cui non ci avventureremo oltre, per il momento!…

22) In questo modo, il codice è davvero molto più pulito e leggibile.

23) Ed ecco il risultato finale:

7. Conclusione

24) Che dire? È stata una breve ma intensa passeggiata sui sentieri delle funzionalità di Cocoa! Spero che questo piccolo tutorial vi abbia fatto imparare qualcosa che ancora non sapevate, e scusate se per caso mi sono dilungato o sono stato mortalmente noioso. L’importante è una funzione che non conoscevate, un indizio, anche una sola parola vi sia stata utile. Certo, si potrebbe completare il tutorial con l’aggiunta di diversi suoni in corrispondenza dei diversi pulsanti premuti, oppure creare un meccanismo in grado di fare lampeggiare dei riquadri a caso e di interrogarvi per vedere se riuscite a ripeterli nell’ordine giusto, proprio come nel gioco!

Non sarebbe complicato, basterebbe un file con qualche istruzione, un NSTimer e magari un contatore che mostri sul display i diversi punteggi realizzati, ma il tempo è poco e non so se possa interessarvi più di tanto. Magari può essere lo spunto per una seconda parte del tutorial, chissà! L’importante è che vi siate divertiti a giocare con me, con Cocoa e con il vostro Mac. A presto!

Alessandro

iPhoneandgo - Lodu - iPhoneandgo@gmail.com
Cresciamo insieme . Developer . Tutorial Pratici | Add your comment

Leave A Reply