Flash As3 Programming
Flash As3 Programming
ACTIONSCRIPT 3.0
™
© 2007 Adobe Systems Incorporated. Tutti i diritti riservati.
Se la presente guida viene distribuita con software che include un accordo di licenza per l’utente finale, la guida e il software in
essa descritto sono concessi in licenza e possono essere usati e copiati solo in conformità con i termini di tale licenza. Ad eccezione
di quanto eventualmente concesso da tale licenza, nessuna parte di questa guida può essere riprodotta, memorizzata in un sistema
per il recupero dati o trasmessa in qualsiasi forma o con qualsiasi mezzo, elettronico, meccanico, di registrazione o altro, senza il
previo consenso scritto da parte di Adobe Systems Incorporated. Il contenuto di questa guida è protetto dalle leggi sui diritti
d’autore, anche se non distribuito con software corredato di accordo di licenza per l’utente finale.
Il contenuto di questa guida viene fornito unicamente a scopo informativo, è soggetto a modifiche senza preavviso e non
comporta alcun impegno per Adobe Systems Incorporated. Adobe Systems Incorporated declina ogni responsabilità per eventuali
errori o imprecisioni presenti in questa guida.
Se si inseriscono in un progetto grafica e immagini esistenti, si tenga presente che tali materiali potrebbero essere protetti dalla
legge sul copyright. L’inserimento non autorizzato di tali materiali nel proprio lavoro potrebbe rappresentare una violazione dei
diritti del titolare del copyright. Assicurarsi sempre di ottenere le eventuali autorizzazioni necessarie dal titolare dei diritti
d’autore.
Tutti i riferimenti a nomi di società negli esempi forniti hanno scopo puramente dimostrativo e non intendono fare riferimento
ad alcuna organizzazione realmente esistente.
Adobe, il logo Adobe, Flex, Flex Builder e Flash Player sono marchi registrati o marchi commerciali di Adobe Systems
Incorporated negli Stati Uniti e/o in altri Paesi.
ActiveX e Windows sono marchi registrati o marchi commerciali di Microsoft Corporation negli Stati Uniti e in altri Paesi.
Macintosh è un marchio di Apple Inc., registrato negli Stati Uniti e in altri Paesi. Tutti gli altri marchi appartengono ai rispettivi
proprietari.
Tecnologia per la compressione e la decompressione vocale concessa in licenza da Nellymoser, Inc. (www.nellymoser.com).
Browser Opera® Copyright © 1995-2002 di Opera Software ASA e dei suoi fornitori. Tutti i diritti riservati.
Adobe Systems Incorporated, 345 Park Avenue, San Jose, California 95110, USA
Avviso agli utenti finali di enti governativi degli Stati Uniti d’America: il software e la documentazione sono “Commercial Items”
(Prodotti commerciali) secondo la definizione contenuta nell’articolo 48 C.F.R. §2.101, costituiti da “Commercial Computer
Software” (Software commerciale per Computer) e “Commercial Computer Software Documentation” (Documentazione relativa
a software commerciale per Computer) secondo la definizione contenuta nell’articolo 48 C.F.R. §12.212 o 48 C.F.R. §227.7202,
secondo i casi. In conformità con l’articolo 48 C.F.R. §12.212 o con gli articoli da 48 C.F.R. §§227.7202-1 a 227.7202-4
incluso, secondo i casi, i “Commercial Computer Software” e “Commercial Computer Software Documentation” vengono
concessi in licenza agli utenti appartenenti al Governo degli Stati Uniti d’America (a) esclusivamente come “Commercial Items” e
(b) con i soli diritti concessi a tutti gli altri utenti finali ai termini e alle condizioni qui contenuti. Tutti i diritti non pubblicati
riservati, ai sensi della legge sul diritto d’autore vigente negli Stati Uniti d’America. Adobe Systems Incorporated, 345 Park
Avenue, San Jose, CA 95110-2704, USA. Nei confronti degli utenti finali del Governo degli Stati Uniti, Adobe accetta di
rispettare tutte le leggi applicabili sul diritto alle pari opportunità, comprese, ove applicabili, le direttive dell’Executive Order
11246, secondo revisione, la sezione 402 del “Vietnam Era Veterans Readjustment Assistance Act” del 1974 (38 USC 4212) e la
sezione 503 del “Rehabilitation Act” del 1973, secondo revisione, oltre ai regolamenti esposti in 41 CFR da 60-1 a 60-60, 60-250
e 60-741. La clausola di azione affermativa e i regolamenti sopra elencati saranno incorporati tramite riferimento.
Indice
3
Creazione di classi personalizzate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Strategie per la progettazione di una classe . . . . . . . . . . . . . . . . . . . . 57
Scrittura del codice per una classe . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
Suggerimenti per l’organizzazione delle classi. . . . . . . . . . . . . . . . . . 60
Esempio: Creazione di un’applicazione di base . . . . . . . . . . . . . . . . . . . 61
Esempi successivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
4
Ereditarietà. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Argomenti avanzati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .184
Esempio: GeometricShapes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .194
5
Creazione di classi di errore personalizzate. . . . . . . . . . . . . . . . . . . . . . 287
Risposte a eventi errore e a errori basati sullo stato . . . . . . . . . . . . . .288
Confronto tra le classi di tipo Error . . . . . . . . . . . . . . . . . . . . . . . . . . . . .292
Classi Error di base ECMAScript. . . . . . . . . . . . . . . . . . . . . . . . . . . . .292
Classi Error di base ActionScript. . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
Classi Error del pacchetto flash.error . . . . . . . . . . . . . . . . . . . . . . . . .296
Esempio: Applicazione CustomErrors . . . . . . . . . . . . . . . . . . . . . . . . . .298
6
Capitolo 12: Programmazione degli elementi visivi . . . . . . . . . . 395
Elementi fondamentali della programmazione degli
elementi visivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395
Classi di visualizzazione di base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .401
Vantaggi dell’elenco di visualizzazione . . . . . . . . . . . . . . . . . . . . . . . . . 403
Operazioni con gli oggetti di visualizzazione . . . . . . . . . . . . . . . . . . . . 407
Proprietà e metodi della classe DisplayObject . . . . . . . . . . . . . . . . 407
Aggiunta di oggetti di visualizzazione all’elenco
di visualizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 408
Uso dei contenitori degli oggetti di visualizzazione . . . . . . . . . . . . 408
Lettura dell’elenco di visualizzazione . . . . . . . . . . . . . . . . . . . . . . . . .413
Impostazione delle proprietà dello stage . . . . . . . . . . . . . . . . . . . . . .415
Gestione degli eventi per gli oggetti di visualizzazione . . . . . . . . . .419
Scelta di una sottoclasse DisplayObject . . . . . . . . . . . . . . . . . . . . . .421
Manipolazione di oggetti di visualizzazione . . . . . . . . . . . . . . . . . . . . . 422
Modifica della posizione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
Panoramica e scorrimento di oggetti di visualizzazione . . . . . . . . 429
Manipolazione delle dimensioni e modifica in scala
degli oggetti. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 430
Controllo della distorsione durante la modifica in scala . . . . . . 432
Memorizzazione nella cache di oggetti di visualizzazione . . . . . . 434
Quando attivare la memorizzazione nella cache . . . . . . . . . . . . 436
Attivazione della memorizzazione di bitmap nella cache . . . . . 438
Impostazione di un colore di sfondo opaco . . . . . . . . . . . . . . . . . 438
Applicazione dei metodi di fusione . . . . . . . . . . . . . . . . . . . . . . . . . . 439
Regolazione dei colori di un oggetto di visualizzazione . . . . . . . . 440
Impostazione dei valori di colore con il codice . . . . . . . . . . . . . . .441
Modifica di effetti di colore e luminosità con il codice . . . . . . . . 442
Rotazione degli oggetti. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 443
Applicazione della dissolvenza agli oggetti . . . . . . . . . . . . . . . . . . . 443
Mascheratura degli oggetti di visualizzazione . . . . . . . . . . . . . . . . . 444
Animazione di oggetti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 447
Caricamento dinamico di contenuto di visualizzazione . . . . . . . . . . . 450
Caricamento di oggetti di visualizzazione. . . . . . . . . . . . . . . . . . . . . 450
Monitoraggio dello stato di avanzamento del caricamento . . . . . .451
Impostazione del contesto di caricamento. . . . . . . . . . . . . . . . . . . . 452
Esempio: SpriteArranger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
7
Uso degli oggetti Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .474
Esempio: Applicazione di una trasformazione di matrice a
un oggetto di visualizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
8
Caricamento di un file SWF esterno . . . . . . . . . . . . . . . . . . . . . . . . . . . 540
Esempio: RuntimeAssetsExplorer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542
9
Capitolo 19: Operazioni con i file video . . . . . . . . . . . . . . . . . . . . 593
Elementi fondamentali del video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
Nozioni fondamentali sul formato Flash Video (FLV) . . . . . . . . . . . . .597
Nozioni fondamentali sulla classe Video . . . . . . . . . . . . . . . . . . . . . . . .598
Caricamento di file video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 599
Controllo della riproduzione video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600
Rilevamento della fine di un flusso video . . . . . . . . . . . . . . . . . . . . . . 601
Streaming di file video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
Nozioni fondamentali sui cue point . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603
Scrittura di metodi di callback per onCuePoint e onMetaData . . . . 604
Impostare la proprietà client dell’oggetto su un oggetto . . . . . . . 605
Creare una classe personalizzata e definire i metodi
per gestire i metodi di callback. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 606
Estendere la classe NetStream e aggiungere i metodi
per gestire i metodi di callback. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .607
Estendere la classe NetStream e renderla dinamica . . . . . . . . . . 608
Impostare la proprietà client dell’oggetto NetStream
su questo valore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610
Uso dei cue point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610
Uso di metadati video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .611
Rilevamento dell’input da videocamera . . . . . . . . . . . . . . . . . . . . . . . . . 615
Nozioni fondamentali sulla classe Camera . . . . . . . . . . . . . . . . . . . . 615
Visualizzazione sullo schermo del contenuto della
videocamera. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 616
Progettazione di un’applicazione per la videocamera . . . . . . . . . . 616
Collegamento alla videocamera di un utente . . . . . . . . . . . . . . . . . . 617
Verifica dell’installazione delle videocamere. . . . . . . . . . . . . . . . . . . 617
Rilevamento delle autorizzazioni per l’accesso alla
videocamera. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 618
Ottimizzazione della qualità video . . . . . . . . . . . . . . . . . . . . . . . . . . . 620
Monitoraggio delle condizioni di riproduzione . . . . . . . . . . . . . . . . .622
Invio del video a un server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .623
Argomenti avanzati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .623
Compatibilità di Flash Player con i file FLV codificati . . . . . . . . . . .623
Informazioni sulla configurazione di file FLV per
l’hosting su un server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .624
Informazioni sull’indirizzamento di file FLV locali in
Macintosh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .625
Esempio: Video Jukebox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .625
10
Capitolo 20: Operazioni con l’audio . . . . . . . . . . . . . . . . . . . . . . 633
Nozioni fondamentali sulle operazioni con l’audio . . . . . . . . . . . . . . . 634
Nozioni fondamentali sull’architettura audio . . . . . . . . . . . . . . . . . . . . 637
Caricamento di file audio esterni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 639
Operazioni con l’audio incorporato. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 642
Operazioni con l’audio in streaming . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
Riproduzione dell’audio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 645
Sospensione e ripresa della riproduzione dell’audio . . . . . . . . . . . 646
Monitoraggio della riproduzione. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 646
Interruzione dell’audio in streaming . . . . . . . . . . . . . . . . . . . . . . . . . . 649
Considerazioni sulla sicurezza durante il caricamento e
la riproduzione dell’audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649
Controllo del volume e della panoramica dell’audio . . . . . . . . . . . . . . 650
Operazioni con i metadati audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
Accesso ai dati audio originari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 653
Rilevamento dell’input audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658
Accesso a un microfono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 658
Instradamento dell’audio del microfono agli altoparlanti locali . . 659
Modifica dell’audio del microfono . . . . . . . . . . . . . . . . . . . . . . . . . . . 660
Rilevamento dell’attività del microfono . . . . . . . . . . . . . . . . . . . . . . . 660
Invio di audio verso e da un server multimediale . . . . . . . . . . . . . . . 662
Esempio: Podcast Player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 662
Lettura dei dati RSS per un canale podcast . . . . . . . . . . . . . . . . . . 664
Semplificazione del caricamento e della riproduzione
dell’audio mediante la classe SoundFacade . . . . . . . . . . . . . . . . . . 664
Visualizzazione dell’avanzamento della riproduzione . . . . . . . . . . 668
Sospensione e ripresa della riproduzione. . . . . . . . . . . . . . . . . . . . . 669
Estensione dell’esempio Podcast Player . . . . . . . . . . . . . . . . . . . . . 670
11
Operazioni di caricamento e scaricamento dei file. . . . . . . . . . . . . . . . 715
Esempio: Creazione di un client Telnet. . . . . . . . . . . . . . . . . . . . . . . . . . 726
Esempio: Caricamento e scaricamento di file . . . . . . . . . . . . . . . . . . . .730
12
Accesso a file multimediali caricati come dati . . . . . . . . . . . . . . . . . . . 836
Caricamento di dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
Caricamento di contenuto incorporato da file SWF importati
in un dominio di sicurezza. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 842
Operazioni con contenuto precedente . . . . . . . . . . . . . . . . . . . . . . . . . 843
Impostazione di autorizzazioni LocalConnection . . . . . . . . . . . . . . . . 844
Controllo dell’accesso a script in una pagina Web host. . . . . . . . . . . 845
Oggetti condivisi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 846
Accesso a fotocamera, microfono, Appunti, mouse e tastiera . . . . . 848
13
14
Informazioni sul manuale
Sommario
Uso del manuale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
Accesso alla documentazione di ActionScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .17
Risorse di apprendimento per ActionScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
15
Uso del manuale
I capitoli del manuale sono organizzati nei seguenti gruppi logici per aiutare il lettore a
individuare più facilmente le aree correlate della documentazione di ActionScript:
Capitoli Descrizione
Capitoli da 5 a 10: tipi di dati e classi di Descrivono i tipi di dati di primo livello di
base di ActionScript 3.0 ActionScript 3.0 che fanno anche parte della
specifica del linguaggio ECMAScript.
Capitoli da 11 a 26: API di Flash Player Descrivono varie funzioni importanti che sono
implementate nei pacchetti e nelle classi
specifiche di Adobe Flash Player 9: gestione
degli eventi, connettività di rete e comunicazioni,
input e output dei file, interfaccia esterna,
modello di sicurezza dell’applicazione e altro
ancora.
Questo manuale contiene anche numerosi file di esempio, che dimostrano i concetti della
programmazione di applicazioni per le classi più importanti e utilizzate più comunemente.
I file di esempio sono inseriti in un pacchetto, in modo che sia facile scaricarli e utilizzarli con
Adobe® Flash® CS3 Professional, e possono includere file wrapper. Tuttavia, il codice di
esempio principale è semplice ActionScript 3.0 che può essere utilizzato in qualsiasi ambiente
di sviluppo.
ActionScript 3.0 può essere scritto e compilato in vari modi:
■ Utilizzando l’ambiente di sviluppo Adobe Flex Builder 2
■ Utilizzando qualunque editor di testo e compilatore della riga di comando, come quello
fornito con Flex Builder 2
■ Utilizzando lo strumento di creazione Adobe® Flash® CS3 Professional
Per ulteriori informazioni sugli ambienti di sviluppo di ActionScript, vedere Capitolo 1,
“Introduzione ad ActionScript 3.0”
Documentazione di Flash
Se si utilizza l’ambiente di sviluppo Flash, è utile consultare i manuali seguenti:
Manuale Descrizione
Uso di Flash Descrive come sviluppare applicazioni Web
dinamiche nell’ambiente di creazione di Flash
Guida di riferimento di ActionScript 2.0 Fornisce esempi di sintassi, uso e codice dei
componenti Flash e dell’API di ActionScript 2.0
Uso dei componenti ActionScript 2.0 Illustra in dettaglio come utilizzare i componenti
di ActionScript 2.0 per sviluppare applicazioni
Flash
Guida introduttiva di Flash Lite 2.x Illustra come utilizzare Adobe® Flash® Lite™ 2.x
per sviluppare applicazioni e fornisce esempi di
sintassi, uso e codice per le funzioni
ActionScript disponibili con Flash Lite 2.x
Sviluppo di applicazioni Flash Lite 2.x Spiega come sviluppare applicazioni Flash
Lite 2.x
Guida di riferimento di ActionScript per Fornisce esempi di sintassi, uso e codice per l’API
Flash Lite 2.x ActionScript 2.0 disponibile in Flash Lite 2.x
Guida introduttiva di Flash Lite 1.x Fornisce un’introduzione a Flash Lite 1.x e
descrive come provare il contenuto utilizzando
l’emulatore Adobe® Device Central CS3
Sviluppo di applicazioni Flash Lite 1.x Descrive come sviluppare applicazioni per i
dispositivi mobili che utilizzano Flash Lite 1.x
Guida di riferimento di ActionScript per Fornisce informazioni sulla sintassi e l’uso degli
Flash Lite 1.x elementi ActionScript disponibili in Flash Lite 1.x
Introduzione ad
ActionScript 3.0
1
Questo capitolo fornisce una panoramica di ActionScript 3.0, la nuova e rivoluzionaria
versione del linguaggio ActionScript.
Sommario
Informazioni su ActionScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Vantaggi di ActionScript 3.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Novità di ActionScript 3.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Compatibilità con le versioni precedenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Informazioni su ActionScript
ActionScript è il linguaggio di programmazione dell’ambiente runtime di Adobe Flash Player.
Rende possibili l’interattività, la gestione dei dati e molte altre operazioni relative al contenuto
e alle applicazioni Flash.
ActionScript viene eseguito dall’AVM (ActionScript Virtual Machine), che fa parte di Flash
Player. Il codice ActionScript viene solitamente compilato in formato codice byte (una sorta di
linguaggio di programmazione generato e interpretato dai computer) mediante un
compilatore, come quello incorporato in Adobe Flash CS3 Professional o in Adobe® Flex™
Builder™ oppure disponibile nell’SDK Adobe® Flex™ e in Flex™ Data Services. Il codice byte
viene incorporato in file SWF, che vengono quindi eseguiti in Flash Player (l’ambiente
runtime).
ActionScript 3.0 offre un solido modello di programmazione che risulta familiare agli
sviluppatori che hanno un’esperienza di base nella programmazione a oggetti. Di seguito sono
elencate alcune delle caratteristiche principali di ActionScript 3.0:
■ Una nuova macchina virtuale ActionScript, chiamata AVM2, che utilizza un nuovo set di
istruzioni per il codice byte e garantisce un notevole miglioramento delle prestazioni.
21
■ Una più moderna base di codice del compilatore, più aderente allo standard ECMAScript
(ECMA 262) e in grado di fornire ottimizzazioni più estese rispetto alle versioni
precedenti del compilatore.
■ Un’API (interfaccia di programmazione applicazioni) più estesa e migliorata, con
controllo di basso livello degli oggetti e modello a oggetti effettivo.
■ Un linguaggio di base fondato sulla bozza di specifica del nuovo linguaggio ECMAScript
(ECMA-262) edizione 4.
■ Un’API XML basata su ECMAScript for XML (E4X), come indicato nella specifica
ECMA-357 edizione 2. E4X è un’estensione di ECMAScript che aggiunge XML al
linguaggio come tipo di dati nativo.
■ Un modello di eventi basato sulla specifica degli eventi DOM (Document Object Model)
Livello 3.
Eccezioni runtime
ActionScript 3.0 segnala più condizioni di errore rispetto alle versioni precedenti del
linguaggio. Le eccezioni runtime sono utilizzate per le condizioni di errore più comuni e
consentono di migliorare il lavoro di debug e di sviluppare applicazioni più efficienti nella
gestione degli errori. Per gli errori runtime sono disponibili tracce di stack annotate con
l’indicazione del file di origine e del numero di riga, che consentono una rapida
individuazione degli errori.
Tipi runtime
In ActionScript 2.0, le annotazioni di tipo fungevano principalmente da aiuto per lo
sviluppatore; in fase di runtime, a tutti i valori veniva assegnato un tipo in modo dinamico.
In ActionScript 3.0, le informazioni sul tipo vengono mantenute in fase di runtime e utilizzate
per vari scopi. Flash Player 9 esegue la verifica runtime del tipo, aumentandone così la
sicurezza per il sistema. Le informazioni sul tipo vengono utilizzate anche per indicare le
variabili nelle rappresentazioni native dei sistemi, ottenendo così migliori prestazioni e una
riduzione dell’uso di memoria.
Classi chiuse
ActionScript 3.0 introduce il concetto di classe chiusa (sealed). Una classe chiusa possiede
unicamente le proprietà e i metodi definiti in fase di compilazione e non consente l’aggiunta
di ulteriori proprietà o metodi. Questa caratteristica consente una verifica più rigorosa in fase
di compilazione e permette di sviluppare programmi più solidi. Inoltre, migliora l’uso della
memoria perché non è necessaria una tabella di hash interna per ogni istanza di oggetto.
Le classi dinamiche possono essere specificate mediante la parola chiave dynamic. Tutte le
classi di ActionScript 3.0 sono chiuse (“sealed”) per impostazione predefinita, ma possono
essere dichiarate dinamiche mediante la parola chiave dynamic.
Espressioni regolari
ActionScript 3.0 include il supporto nativo per le espressioni regolari e permette quindi di
trovare e modificare rapidamente stringhe di codice. ActionScript 3.0 implementa il supporto
delle espressioni regolari così come sono definite nella specifica del linguaggio ECMAScript
edizione 3 (ECMA-262).
Può scambiare script con Solo ActionScript 1.0 e 2.0† ActionScript 3.0‡
contenuto creato in
* Contenuto eseguito in Flash Player 9 o versioni successive. Il contenuto eseguito in Flash
Player 8 o versioni precedenti può caricare, visualizzare, eseguire e scambiare script solo
in ActionScript 1.0 e 2.0.
† ActionScript 3.0 tramite Local Connection.
‡ ActionScript 1.0 e 2.0 tramite LocalConnection.
Guida introduttiva ad
ActionScript
2
Questo capitolo offre una panoramica del linguaggio di programmazione ActionScript e pone
le basi di cui l’utente ha bisogno per capire i concetti e gli esempi presentati negli altri capitoli
del manuale. Il contenuto del capitolo si articola in due blocchi: la descrizione delle nozioni
fondamentali sulla programmazione, con relativa applicazione nell’ambiente ActionScript, e le
operazioni essenziali per organizzare e creare un’applicazione tramite ActionScript.
Sommario
Nozioni fondamentali sulla programmazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Operazioni con gli oggetti. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Elementi comuni dei programmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Esempio: Porzione del portfolio animazioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Creazione di applicazioni con ActionScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Creazione di classi personalizzate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Esempio: Creazione di un’applicazione di base. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
Esempi successivi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
29
Nozioni fondamentali sulla
programmazione
Dal momento che ActionScript è un linguaggio di programmazione, è utile avere presenti
alcuni concetti fondamentali riguardanti la programmazione.
In questo caso, abbiamo istruito il computer di creare la variabile value1, che potrà contenere
solo dati di tipo Number (“Number” è un tipo di dati specifico di ActionScript che
corrisponde a “valore numerico”). In alternativa, è possibile associare immediatamente un
valore alla variabile:
var value2:Number = 17;
Tipi di dati
ActionScript mette a disposizione vari tipi di dati da utilizzare per le variabili. Alcuni di essi
possono essere considerati tipi di dati “semplici” o “fondamentali”:
■ String: unità di testo, come un nome o il capitolo di un libro
■ Dati numerici: ActionScript 3.0 comprende tre sottogruppi specifici per i dati numerici:
■ Number: qualsiasi valore numerico, con o senza decimali
■ int: numero intero senza decimali
■ uint: numero intero senza segno, vale a dire un numero intero non negativo
■ Boolean: tipo di dati i cui unici valori possibili sono vero o falso, che descrive, ad esempio,
se uno switch è attivo o se due valori sono uguali
I tipi di dati semplici rappresentano una porzione di dati singola: ad esempio, un unico
numero o un’unica sequenza di testo. Tuttavia, la maggior parte dei tipi di dati definiti tramite
ActionScript sono dati complessi in quanto rappresentano un gruppo di valori combinati tra
loro. Per esempio, una variabile del tipo Date rappresenta un valore unico, cioè una data
precisa. Tuttavia, il valore della data è rappresentato da una serie di valori: il giorno, il mese,
l’anno, le ore, i minuti, i secondi e così via, vale a dire da una serie di numeri distinti.
Di conseguenza, mentre noi concepiamo una data come un valore singolo (e lo possiamo
trattare come tale impostando una variabile Date), il computer considera la data come una
serie di valori che, combinati, definiscono un momento preciso.
La più parte dei tipi di dati incorporati, e dei tipi di dati definiti dai programmatori, sono in
realtà dati complessi. Alcuni dei tipi di dati complessi più conosciuti sono:
■ MovieClip: simbolo di clip filmato
■ TextField: campo di testo dinamico o di input
■ SimpleButton: simbolo di pulsante
■ Date: indicazione temporale precisa (data e ora)
Proprietà
Una proprietà rappresenta una porzione di dato che, combinata con altre, fa parte
dell’oggetto. Un oggetto “song” potrebbe avere le proprietà artist e title; la classe
MovieClip ha proprietà del tipo rotation, x, width e alpha. Le proprietà vengono utilizzate
come se fossero variabili singole, in realtà, si può addirittura considerare le proprietà come
variabili secondarie di un oggetto.
Ecco alcuni esempi dell’impiego di proprietà nel codice ActionScript. Questa riga di codice
sposta il filmato clip denominato square nella coordinata x di 100 pixel:
square.x = 100;
Questa riga di codice utilizza la proprietà rotation per imprimere al filmato clip square la
stessa rotazione del filmato clip triangle:
square.rotation = triangle.rotation;
Questa riga di codice modifica la scala orizzontale del filmato clip square su un valore di una
volta e mezzo superiore rispetto all’originale:
square.scaleX = 1.5;
Notare la struttura che accomuna queste righe di codice: si scrive la variabile (square,
triangle) come nome dell’oggetto seguita da un punto (.) a sua volta seguito dal nome della
proprietà (x, rotation, scaleX). Il punto, conosciuto come operatore punto, introduce un
elemento secondario di un oggetto. L’intera struttura, “nome variabile-punto-nome
proprietà,” viene considerata un’unica variabile che dà il nome a un singolo valore della
memoria del computer.
Questa riga di codice indica di interrompere la riproduzione del filmato clip denominato
shortFilm (l’indicatore di riproduzione si ferma nel punto in cui si trova, come succede
quando si preme il tasto pausa di un video):
shortFilm.stop();
Risulta chiaro che si invocano i metodi proprio come le proprietà: si scrive il nome
dell’oggetto (una variabile) seguito da un punto, poi si aggiunge il nome del metodo seguito
da due parentesi. Le parentesi indicano la chiamata al metodo, vale a dire che si sta
richiedendo all’oggetto di eseguire quella determinata azione. A volte le parentesi possono
contenere dei valori o delle variabili che forniscono informazioni aggiuntive da utilizzare per
eseguire l’azione. Questi valori aggiuntivi vengono definiti parametri del metodo. Per esempio,
per il metodo gotoAndStop() è necessario specificare il fotogramma dove l’indicatore di
riproduzione si deve fermare, pertanto richiede la specifica di un parametro tra parentesi. Altri
metodi, come play() e stop(), sono sufficientemente chiari e non richiedono informazioni
supplementari, anche se le due parentesi del nome vengono mantenute.
Contrariamente alle proprietà e alle variabili, i metodi non sono utilizzati come segnaposto di
valori, nonostante alcuni di essi possano eseguire dei calcoli e restituire un risultato che può
essere utilizzato come una variabile. Per esempio, il metodo toString() della classe Number
converte il valore numerico in una stringa di testo:
var numericData:Number = 9;
var textData:String = numericData.toString();
Eventi
Abbiamo descritto un programma per computer come una serie di istruzioni che il computer
esegue in sequenza. I programmi più semplici non sono niente di più: una serie di procedure
che il computer esegue e terminate le quali il programma finisce. I programmi creati con
ActionScript, tuttavia, sono progettati per non interrompersi e attendere l’input da parte
dell’utente o il verificarsi di altre condizioni. Gli eventi sono il meccanismo che definisce le
istruzioni che il computer esegue e la relativa sequenza.
In sostanza, gli eventi sono condizioni che si verificano di cui ActionScript è consapevole e a
cui è in grado di reagire. Molti eventi solo collegati all’interazione dell’utente, la selezione di
un pulsante o la pressione di un tasto della tastiera, ma ne esistono anche di altri tipi. Per
esempio, se si usa ActionScript per caricare un’immagine esterna, esiste un evento che può
avvertire quando l’immagine è stata caricata completamente. In pratica, durante l’esecuzione
di un programma ActionScript, Adobe Flash Player “rimane in ascolto” e attende il verificarsi
di determinati eventi; quando questi si realizzano, Flash esegue il codice ActionScript
specificato per quei particolari eventi.
eventSource.addEventListener(EventType.EVENT_NAME, eventResponse);
Questo esempio di codice svolge due compiti. Definisce una funzione, vale a dire che specifica
le azioni che devono avvenire in risposta all’evento. In secondo luogo, chiama il metodo
addEventListener() dell’oggetto di origine, in pratica associando la funzione all’evento, in
modo che quando si verifica l’evento vengono attivate le azioni descritte nella funzione.
Ora affronteremo ogni compito in maggiore dettaglio.
Una funzione rappresenta un modo per raggruppare insieme varie azioni creando un’unica
entità dotata di un nome proprio. Le funzioni sono quasi identiche ai metodi, con l’unica
differenza che non sono necessariamente associate a una classe specifica; infatti, si potrebbe
definire i metodi come funzioni associate a una classe specifica. Una funzione per la gestione
di eventi deve avere obbligatoriamente un nome (in questo caso eventResponse) e un
parametro (nel nostro esempio: eventObject). La specifica di un parametro per una funzione
equivale alla dichiarazione di una variabile, di conseguenza, per il parametro è necessario
definire il tipo di dati. Per ogni evento viene definita una classe di ActionScript e il tipo di dati
specificato per il parametro della funzione è sempre la classe associata all’evento a cui si
intende rispondere. Infine, tra le parentesi graffe ({ ... }), scrivere le procedure che il computer
deve eseguire quando l’evento si verifica.
Una volta scritta la funzione di gestione degli eventi, è necessario comunicare all’oggetto di
origine dell’evento (l’oggetto su cui si verifica l’evento, ad esempio, il pulsante) che la funzione
deve essere richiamata nel momento in cui l’evento si verifica. A questo scopo, si chiama il
metodo addEventListener() dell’oggetto; infatti, tutti gli oggetti associati ad eventi sono
associati anche al metodo addEventListener(). Il metodo addEventListener() accetta
due parametri:
■ Prima di tutto, il nome dell’evento specifico a cui rispondere. Come già spiegato in
precedenza, ogni evento è collegato a una classe specifica e nella classe ogni evento ha un
valore predefinito speciale, o nome, che l’utente deve usare come primo parametro del
metodo.
■ Secondariamente, il nome della funzione di risposta all’evento. Si noti che i nomi di
funzione passati come parametri vanno scritti senza parentesi.
myButton.addEventListener(MouseEvent.CLICK, eventResponse);
c. Nel momento in cui viene chiamata la funzione eventResponse(), il suo codice viene
eseguito e le azioni specificate vengono attivate.
function playMovie(event:MouseEvent):void
{
this.play();
}
playButton.addEventListener(MouseEvent.CLICK, playMovie);
entryText.addEventListener(TextEvent.TEXT_INPUT, updateOutput);
linkButton.addEventListener(MouseEvent.CLICK, gotoAdobeSite);
È possibile usare l’operatore new per creare un’istanza dell’oggetto anche per i tipi di dati
che consentono di creare istanze tramite espressioni letterali. Queste due righe di
codice, ad esempio, generano lo stesso risultato:
var someNumber:Number = 6.33;
var someNumber:Number = new Number(6.33);
È importante avere dimestichezza con il metodo new ClassName() per la creazione degli
oggetti perché se si presenta la necessità di creare un’istanza di un tipo di dati ActionScript per
cui non è prevista una rappresentazione visiva (per cui non si può inserire un elemento sullo
stage di Flash né usare la modalità Design dell’editor MXML di Flex Builder), l’unica opzione
di cui si dispone è creare l’oggetto direttamente in ActionScript usando l’operatore new.
In particolare, Flash permette di usare l’operatore new per creare un’istanza di un simbolo di
filmato clip definito nella Libreria ma non inserito sullo stage. Per ulteriori informazioni a
riguardo, vedere “Creazione di oggetti MovieClip mediante ActionScript” a pagina 536.
Operatori
Gli operatori sono simboli speciali (o, più raramente, parole) che permettono di eseguire dei
calcoli. Vengono utilizzati prevalentemente per operazioni aritmetiche e per comparare fra
loro dei valori. Come regola generale, un operatore utilizza uno o più valori per estrapolare un
risultato. Ad esempio:
■ L’operatore di somma (+) somma tra loro più valori e restituisce un numero come
risultato:
var sum:Number = 23 + 32;
■ L’operatore di uguaglianza (==) confronta due valori per stabilire se sono uguali e
restituisce un valore booleano (true o false):
if (dayOfWeek == "Wednesday")
{
takeOutTrash();
}
■ Commenti su più righe: Un commento che occupa più righe comprende un indicatore di
inizio (/*), il commento vero e proprio seguito da un indicatore di fine (*/). Tutto il testo
scritto tra i due indicatori viene ignorato dal computer, indipendentemente dal numero di
righe occupate:
/*
Si può inserire una descrizione lunghissima, che spieghi
l’uso di una particolare funzione o il significato di un’intera
sezione di codice.
Per scrivere il codice per avviare l’animazione quando si fa clic sul pulsante play:
1. Al termine del codice inserito nei punti precedenti, aggiungere due righe vuote.
2. Inserire il codice seguente alla fine dello script:
function startMovie(event:MouseEvent):void
{
this.play();
}
Questa riga di codice registra la funzione startMovie() come listener per l’evento click
di playButton. In altre parole, fa in modo che quando si fa clic sul pulsante di nome
playButton, venga chiamata la funzione startMovie().
Per scrivere codice per indirizzare il browser a un URL quando si fa clic sul
pulsante home page:
1. Al termine del codice inserito nei punti precedenti, aggiungere due righe vuote.
2. Inserire il codice seguente alla fine dello script:
function gotoAuthorPage(event:MouseEvent):void
{
var targetURL:URLRequest = new URLRequest("http://example.com/");
navigateToURL(targetURL);
}
Questa riga di codice registra la funzione gotoAuthorPage() come listener per l’evento
click di homeButton. In altre parole, fa in modo che quando si fa clic sul pulsante di
nome homeButton, venga chiamata la funzione gotoAuthorPage().
Prova dell’applicazione
A questo punto, l’applicazione dovrebbe essere completamente funzionante. Per verificarlo,
effettuare una prova.
Si sottraggono a questa regola le classi di primo livello, che non sono definite
all’interno del pacchetto.
N OT A
■ Scrivere del codice che faccia esplicitamente riferimento al nome della classe
(generalmente si procede dichiarando una variabile con la classe come tipo di dati e si
memorizza nella variabile un’istanza della classe). Inserendo un riferimento a un nome
di classe diverso nel codice ActionScript, si indica al compilatore di caricare la
definizione di tale classe. Ad esempio, data una classe esterna chiamata Box,
l’istruzione seguente crea una nuova istanza di tale classe:
var smallBox:Box = new Box(10,20);
Quando incontra per la prima volta il riferimento alla classe Box, il compilatore cerca
nel codice di origine caricato la definizione della classe Box.
Flex Builder
Adobe Flex Builder è lo strumento privilegiato per la creazione di progetti con struttura Flex.
Oltre al layout visivo e agli strumenti di modifica MXML, Flex Builder offre un editor di
ActionScript completamente funzionale che permette di creare progetti Flex o contenenti
esclusivamente codice ActionScript. Le applicazioni Flex offrono svariati vantaggi tra cui: una
ricca gamma di componenti dell’interfaccia utente prestabiliti, controlli flessibili per il layout
dinamico e meccanismi incorporati per l’interazione con origini dati esterne e il collegamento
di dati esterni agli elementi dell’interfaccia utente. Tuttavia, in ragione del codice
supplementare necessario per attivare queste funzioni, le applicazioni Flex generano file SWF
di dimensioni superiori e non permettono una facile riassegnazione totale degli skin come le
controparti di Flash.
Usare Flex Builder per creare applicazioni Internet complete e ricche di dati con Flex, per
modificare il codice ActionScript e MXML e per creare un’anteprima visiva dell’applicazione,
tutto usando un unico strumento.
Il termine public indica che la classe è accessibile da qualsiasi altra riga di codice.
Per alternative, vedere “Attributi dello spazio dei nomi per il controllo dell’accesso”
a pagina 154.
3. Digitare un’istruzione che indichi il nome del pacchetto che ospiterà il proprio pacchetto.
La sintassi è composta dalla parola package, seguita dal nome assegnato al pacchetto
seguito, a sua volta, da due parentesi graffe (che racchiudono il blocco di istruzioni class).
Ad esempio, intervenendo sul codice dell’esempio precedente si ottiene:
package mypackage
{
public class MyClass
{
}
}
4. Definire tutte le proprietà della classe usando l’istruzione var all’interno del corpo della
classe; la sintassi corrisponde a quella utilizzata per dichiarare una variabile (con l’aggiunta
del modificatore public). Ad esempio, l’aggiunta di queste righe tra le parentesi graffe della
definizione della classe crea le proprietà textVariable, numericVariable e
dateVariable:
public var textVariable:String = "some default value";
public var numericVariable:Number = 17;
public var dateVariable:Date;
5. Definire tutti i metodi della classe replicando la sintassi utilizzata per definire una funzione.
Ad esempio:
■ Per creare il metodo myMethod(), digitare:
public function myMethod(param1:String, param2:Number):void
{
// esegue un’operazione con i parametri
}
La classe Greeter include un unico metodo sayHello(), che restituisce una stringa con il
testo “Hello” al nome utente che viene specificato.
2. Selezionare File > Salva per salvare il file ActionScript.
La classe Greeter è ora pronta per essere utilizzata in un’applicazione Flash o Flex.
8. Salvare il file.
Procedere con la sezione “Pubblicazione e prova dell’applicazione ActionScript” a pagina 64.
/**
* Builds a greeting string using the given name.
*/
public function sayHello(userName:String = ""):String
{
var greeting:String;
if (userName == "")
{
greeting = "Hello. Please type your user name, and then press
the Enter key.";
}
else if (validName(userName))
{
greeting = "Hello, " + userName + ".";
}
else
{
greeting = "Sorry, " + userName + ", you are not on the list.";
}
return greeting;
}
/**
* Checks whether a name is in the validNames list.
*/
public static function validName(inputName:String = ""):Boolean
{
if (validNames.indexOf(inputName) > -1)
{
return true;
}
else
{
return false;
}
}
}
}
3. Selezionare lo strumento Testo nel pannello Strumenti, quindi creare due nuovi campi di
testo sullo stage, uno accanto all’altro e direttamente sotto il campo mainText già presente.
4. Nel primo campo di testo, digitare il testo User Name: come etichetta.
5. Selezionare l’altro campo di testo aggiunto e, nella finestra di ispezione Proprietà,
selezionare Testo di input come tipo di campo. Digitare textIn come nome di istanza.
6. Fare clic sul primo fotogramma della linea temporale principale.
textIn.addEventListener(KeyboardEvent.KEY_UP, keyPressed);
function keyPressed(event:Event):void
{
if (event.keyCode == Keyboard.ENTER)
{
mainText.text = myGreeter.sayHello(textIn.text);
}
}
textIn.addEventListener(KeyboardEvent.KEY_UP, keyPressed);
function keyPressed(event:Event):void
{
if (event.keyCode == Keyboard.ENTER)
{
mainText.text = myGreeter.sayHello(textIn.text);
}
}
8. Salvare il file.
9. Selezionare Controllo > Prova filmato per eseguire l’applicazione.
Viene richiesto di immettere un nome utente. Se il nome immesso è valido
(Sammy, Frank o Dean), l’applicazione visualizza il messaggio di conferma “hello”.
Per creare un documento Flash per provare gli esempi contenuti nei capitoli:
1. Creare un documento Flash e salvarlo sul disco rigido.
2. Per visualizzare i valori di prova in un campo di testo sullo stage, attivare lo strumento
Testo e creare un nuovo campo di testo dinamico sullo stage. L’ideale è un campo di testo
largo e alto con il tipo di riga Multiriga e il bordo attivato. Nella finestra di ispezione
Proprietà, assegnare al campo di testo un nome di istanza (ad esempio “outputText”). Per
scrivere i valori nel campo di testo, aggiungere al codice di esempio un codice che chiama
il metodo appendText() (come descritto sotto).
3. In alternativa, per visualizzare i risultati dell’esempio, è possibile aggiungere al codice di
esempio una chiamata alla funzione trace() (come descritto sotto).
4. Per provare un determinato esempio, copiare il codice nel pannello Azioni; se necessario,
aggiungere una chiamata alla funzione trace() oppure un valore al campo di testo
utilizzando il relativo metodo appendText().
5. Dal menu principale, selezionare Controllo > Prova filmato per creare un file SWF e
visualizzare i risultati.
è possibile copiare il codice nel pannello Azioni, quindi aggiungere una chiamata alla
funzione trace(), come mostrato di seguito, per provare il risultato del codice:
var albumName:String = "Three for the money";
trace("albumName =", albumName);
Ciascuna chiamata alla funzione trace() può richiedere più parametri che vengono legati
tra loro per formare una singola riga stampata. Al termine di ciascuna chiamata viene
aggiunta un’interruzione di riga, in modo che le chiamate separate vengano stampate su
righe separate.
■ Un campo di testo sullo stage: se si preferisce non utilizzare la funzione trace(), è
possibile creare un campo di testo dinamico sullo stage mediante lo strumento Testo e
scrivere i valori in questo campo per visualizzare i risultati di un codice. Il metodo
appendText() della classe TextField può essere utilizzato per aggiungere un valore stringa
al termine del contenuto del campo di testo. Per accedere a un campo di testo utilizzando
ActionScript, assegnarvi un nome di istanza nella finestra di ispezione Proprietà.
Ad esempio, se il campo di testo presenta il nome di istanza outputText, il codice
seguente può essere utilizzato per controllare il valore della variabile albumName:
var albumName:String = "Three for the money";
outputText.appendText("albumName = ");
outputText.appendText(albumName);
Esempi successivi 69
Come indica l’esempio, il metodo appendText() aggiunge il testo nella stessa riga del
contenuto precedente, pertanto è possibile aggiungere più valori alla stessa riga di testo
utilizzando più chiamate al metodo appendText(). Per fare in modo che il testo venga
scritto nella riga successiva, è possibile aggiungere un carattere nuova riga ("\n"):
outputText.appendText("\n"); // adds a line break to the text field
Linguaggio e
sintassi ActionScript
3
ActionScript 3.0 comprende sia il linguaggio ActionScript di base che l’API di Adobe Flash
Player. Il linguaggio di base è quella parte di ActionScript che implementa la bozza di specifica
del nuovo linguaggio ECMAScript (ECMA-262) edizione 4. L’API di Flash Player fornisce
l’accesso programmatico a Flash Player.
Questo capitolo offre una breve introduzione al linguaggio ActionScript e alla sua sintassi.
Dopo averlo letto si avrà una conoscenza di base di come lavorare con i tipi di dati e le
variabili, utilizzare la sintassi corretta e controllare il flusso di dati nel programma.
Sommario
Panoramica del linguaggio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Oggetti e classi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
Pacchetti e spazi dei nomi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Variabili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Tipi di dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Sintassi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .110
Operatori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .116
Istruzioni condizionali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Ripetizione ciclica. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Funzioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
71
Panoramica del linguaggio
Gli oggetti costituiscono il cuore del linguaggio ActionScript 3.0, i suoi blocchi costitutivi
fondamentali. Ogni variabile che si dichiara, ogni funzione che si scrive e ogni istanza di classe
che si crea è un oggetto. Si può pensare a un programma ActionScript 3.0 come se fosse un
gruppo di oggetti che svolgono certe attività, rispondono agli eventi e comunicano gli uni con
gli altri.
I programmatori che utilizzano la programmazione a oggetti (OOP) in Java o C++ possono
considerare gli oggetti come dei moduli che contengono due tipi di membri: i dati,
memorizzati in variabili membro o proprietà, e i comportamenti, accessibili mediante metodi.
La bozza ECMAScript edizione 4, lo standard sul quale è basato ActionScript 3.0, definisce gli
oggetti in un modo simile ma leggermente diverso. Nella bozza ECMAScript, infatti, gli
oggetti sono semplicemente raccolte di proprietà, le quali sono contenitori non solo di dati,
ma anche di funzioni e altri oggetti. Se una funzione è associata a un oggetto in questo modo,
prende il nome di metodo.
Sebbene la definizione della bozza ECMAScript possa sembrare un po’ strana ai
programmatori Java o C++, in pratica la definizione dei tipi di oggetto con le classi
ActionScript 3.0 è molto simile al modo in cui le classi vengono definite in Java o C++.
La distinzione tra le due definizioni di oggetto è importante ai fini della discussione sul
modello di oggetti di ActionScript e per altri argomenti avanzati, ma nella maggior parte delle
situazioni il termine proprietà equivale a variabile membro di classe e si contrappone a
metodo. La Guida di riferimento del linguaggio e dei componenti ActionScript 3.0, ad esempio,
usa il termine proprietà per indicare le variabili o le proprietà getter-setter, e il termine metodi
per indicare le funzioni che fanno parte di una classe.
Una sottile differenza tra le classi di ActionScript e quelle di Java o C++ è rappresentata dal
fatto che in ActionScript le classi non sono semplicemente entità astratte, bensì sono
rappresentate da oggetti di classe in cui vengono memorizzate le proprietà e i metodi della
classe. Ciò rende possibile l’uso di tecniche che possono sembrare inusuali ai programmatori
Java e C++, come l’inclusione di istruzioni o di codice eseguibile al livello principale di una
classe o di un pacchetto.
Un’altra differenza tra le classi ActionScript e le classi Java o C++ è costituita dal fatto che ogni
classe ActionScript possiede un elemento chiamato oggetto prototipo. Nelle versioni precedenti
di ActionScript, gli oggetti prototipo, collegati tra loro nelle catene di prototipi, costituivano
insieme la base dell’intera gerarchia di ereditarietà delle classi. In ActionScript 3.0, invece, gli
oggetti prototipo svolgono una funzione secondaria nel sistema dell’ereditarietà. L’oggetto
prototipo può tuttavia essere ancora utile come alternativa a proprietà e metodi statici quando
si desidera condividere una proprietà e il relativo valore tra tutte le istanze di una classe.
Oggetti e classi
In ActionScript 3.0 ogni oggetto è definito da una classe. Una classe può essere considerata
come un modello di base per un tipo di oggetto. Le definizioni di classe possono riguardare
variabili e costanti, che memorizzano valori di dati, oppure metodi, ovvero funzioni che
incorporano un comportamento associato alla classe. I valori memorizzati nelle proprietà
possono essere valori di base (primitive values) o altri oggetti. I valori di base sono numeri,
stringhe o valori booleani.
ActionScript contiene una serie di classi incorporate che fanno parte del linguaggio di base.
Alcune di tali classi, quali Number, Boolean e String, rappresentano i valori di base disponibili
in ActionScript. Altre, come Array, Math e XML, definiscono oggetti più complessi che fanno
parte dello standard ECMAScript.
Tutte le classi, incorporate o definite dall’utente, derivano dalla classe Object. Per i
programmatori che hanno già utilizzato ActionScript in precedenza è importante notare che il
tipo di dati Object non è più quello predefinito, anche se tutte le altre classi derivano ancora
da esso. In ActionScript 2.0 le due righe di codice seguenti erano equivalenti perché l’assenza
di un’annotazione di tipo comportava che una variabile fosse del tipo Object:
var someObj:Object;
var someObj;
ActionScript 3.0 invece introduce il concetto di “variabili senza tipo”, che possono essere
indicate nei due modi seguenti:
var someObj:*;
var someObj;
Una variabile senza tipo non è la stessa cosa di una variabile del tipo Object. La differenza
fondamentale consiste nel fatto che le variabili senza tipo possono contenere il valore speciale
undefined, mentre una variabile del tipo Object non può.
Oggetti e classi 73
Si possono definire classi personalizzate utilizzando la parola chiave class. È possibile
dichiarare le proprietà delle classi in tre modi: le costanti vengono definite con la parola chiave
const, le variabili con la parola chiave var e le proprietà getter/setter utilizzando gli attributi
get e set in una dichiarazione di metodo. I metodi vengono dichiarati con la parola chiave
function.
Un’istanza di una classe viene creata utilizzando l’operatore new. Nell’esempio seguente viene
creata un’istanza della classe Data chiamata myBirthday.
var myBirthday:Date = new Date();
Pacchetti
In ActionScript 3.0, i pacchetti sono implementati insieme agli spazi dei nomi, ma non sono
la stessa cosa. Quando si dichiara un pacchetto, si sta implicitamente creando un tipo speciale
di spazio dei nomi con la garanzia che sarà noto in fase di compilazione. Al contrario, uno
spazio dei nomi creato esplicitamente non è necessariamente noto in fase di compilazione.
Nell’esempio seguente viene utilizzata la direttiva package per creare un pacchetto semplice
che contiene un’unica classe:
package samples
{
public class SampleCode
{
public var sampleGreeting:String;
public function sampleFunction()
{
trace(sampleGreeting + " from sampleFunction()");
}
}
}
Molti sviluppatori, specialmente quelli con esperienza Java, potrebbero scegliere di collocare
solo le classi al livello principale di un pacchetto. Tuttavia, ActionScript 3.0 supporta non solo
le classi in tale posizione, ma anche le variabili, le funzioni e persino le istruzioni. Uno degli
usi avanzati di questa caratteristica consiste nel definire uno spazio dei nomi al livello
principale di un pacchetto, in modo che sia disponibile a tutte le classi del pacchetto. Si noti,
tuttavia, che soltanto due specificatori di accesso (public e internal) sono consentiti al
livello principale di un pacchetto. A differenza di Java, che consente di dichiarare come private
le classi nidificate, ActionScript 3.0 non supporta né le classi nidificate né quelle private.
Per molti altri aspetti, tuttavia, i pacchetti di ActionScript 3.0 sono simili a quelli del
linguaggio di programmazione Java. Come si può notare nell’esempio precedente, i
riferimenti ai nomi completi dei pacchetti vengono espressi utilizzando l’operatore punto (.),
proprio come in Java. È possibile sfruttare i pacchetti per organizzare il codice in una struttura
gerarchica intuitiva che possa essere utilizzata da altri programmatori. In questo modo si
facilita la condivisione del codice, poiché si possono creare pacchetti personalizzati da mettere
a disposizione degli altri e utilizzare nel proprio codice pacchetti creati da altri programmatori.
Inoltre, l’uso dei pacchetti fa sì che i nomi di identificazione utilizzati siano univoci e non in
conflitto con quelli di altri pacchetti. Si potrebbe addirittura sostenere che questo sia il
vantaggio principale dei pacchetti. Ad esempio, si supponga che due programmatori abbiano
deciso di condividere il loro codice e che ciascuno dei due abbia creato una classe chiamata
SampleCode. Senza i pacchetti si creerebbe un conflitto tra i nomi e l’unica soluzione sarebbe
quella di rinominare una delle due classi. Grazie ai pacchetti, invece, il conflitto viene evitato
facilmente collocando una o (preferibilmente) entrambe le classi in pacchetti con nomi
univoci.
È anche possibile includere dei punti (.) incorporati in un pacchetto per creare pacchetti
nidificati, allo scopo di realizzare un’organizzazione gerarchica dei pacchetti. Un buon
esempio di questo caso è il pacchetto flash.xml dell’API di Flash Player, che è nidificato
all’interno del pacchetto flash.
L’API di Flash Player è organizzata quasi interamente all’interno del pacchetto flash.
Ad esempio, il pacchetto flash.display contiene l’API dell’elenco di visualizzazione, e il
pacchetto flash.events contiene il nuovo modello di eventi.
Creazione di pacchetti
ActionScript 3.0 offre una notevole flessibilità nell’organizzazione di pacchetti, classi e file di
origine. Le versioni precedenti di ActionScript consentivano l’uso di un’unica classe per ogni
file di origine e imponevano che il nome del file di origine corrispondesse a quello della classe.
ActionScript 3.0 invece permette di includere più classi nello stesso file di origine, ma una sola
classe di ogni file può essere resa disponibile al codice esterno al file stesso. In altre parole, solo
una classe di ogni file può essere dichiarata all’interno di una dichiarazione di pacchetto.
Le eventuali altre classi devono essere dichiarate all’esterno, pertanto risultano invisibili al
codice esterno al file di origine. Il nome della classe dichiarata nella definizione del pacchetto
deve corrispondere al nome del file di origine.
oppure
import samples.SampleCode;
In generale, le istruzioni import devono essere scritte nel modo più specifico possibile. Se si
prevede di utilizzare solo la classe SampleCode del pacchetto samples, si deve importare solo
la classe SampleCode anziché l’intero pacchetto al quale appartiene. L’importazione di interi
pacchetti può determinare conflitti imprevisti tra i nomi.
Man mano che aumentano i livelli di nidificazione dei pacchetti, diminuisce la leggibilità del
codice. Nei casi in cui si è sicuri che la presenza di identificatori ambigui non rappresenta un
problema, l’uso degli identificatori semplici consente di ottenere codice più leggibile.
Ad esempio, il codice che crea un’istanza della classe SampleCode è molto più semplice se si
include solo l’identificatore di classe:
var mySample:SampleCode = new SampleCode();
Se si tenta di utilizzare nomi di identificatori senza aver prima importato il pacchetto o la
classe corrispondente, il compilatore non è in grado di trovare le definizioni di classe. D’altro
canto, tuttavia, se si importa un pacchetto o una classe e si tenta di definire un nome che è in
conflitto con un nome importato, viene generato un errore.
Quando si crea un pacchetto, lo specificatore di accesso predefinito per tutti i membri del
pacchetto è internal, vale a dire che, per impostazione predefinita, tutti i membri del
pacchetto sono visibili soltanto agli altri membri dello stesso pacchetto. Se si desidera che una
classe sia disponibile al codice esterno al pacchetto, deve essere dichiarata come public.
Ad esempio, il pacchetto seguente contiene due classi, SampleCode e CodeFormatter:
// file SampleCode.as
package samples
{
public class SampleCode {}
}
// file CodeFormatter.as
package samples
{
class CodeFormatter {}
}
Se si desidera che ambedue le classi siano disponibili al codice esterno al pacchetto, occorre
dichiarare entrambe come public. Non è possibile applicare l’attributo public alla
dichiarazione del pacchetto.
I nomi completi sono utili per risolvere conflitti tra nomi che potrebbero verificarsi quando si
usano i pacchetti. Uno scenario di questo tipo si potrebbe presentare se si importano due
pacchetti che definiscono classi con lo stesso identificatore. Ad esempio, esaminare il
pacchetto seguente, che contiene a sua volta una classe chiamata SampleCode:
package langref.samples
{
public class SampleCode {}
}
Il compilatore non ha modo di sapere quale classe SampleCode deve essere utilizzata. Per
risolvere il conflitto, è necessario utilizzare il nome completo di ciascuna classe, come indicato
di seguito:
var sample1:samples.SampleCode = new samples.SampleCode();
var sample2:langref.samples.SampleCode = new langref.samples.SampleCode();
N O TA
Quando una definizione non è preceduta da un attributo namespace, il suo nome viene
qualificato dallo spazio dei nomi predefinito internal, in base al quale la definizione è
visibile unicamente ai chiamanti interni allo stesso pacchetto. Se è impostata la modalità
rigorosa, il compilatore genera un’avvertenza per segnalare che lo spazio dei nomi internal
viene applicato a tutti gli identificatori privi di attributo namespace. Per far sì che un
identificatore sia disponibile senza limiti, è necessario anteporre esplicitamente al suo nome
l’attributo public. Nell’esempio di codice precedente, sampleGreeting e
sampleFunction() hanno entrambi il valore internal per lo spazio dei nomi.
L’utilizzo degli spazi dei nomi prevede tre passaggi fondamentali. Innanzi tutto, occorre
definire lo spazio dei nomi mediante la parola chiave namespace. Ad esempio, il codice
seguente definisce lo spazio dei nomi version1:
namespace version1;
In secondo luogo, si applica lo spazio dei nomi utilizzandolo al posto di uno specificatore di
accesso in una proprietà o nella dichiarazione di un metodo. L’esempio seguente inserisce una
funzione denominata myFunction() nello spazio dei nomi version1:
version1 function myFunction() {}
È possibile inoltre utilizzare un nome qualificato per fare riferimento alla funzione
myFunction(), come nell’esempio seguente:
version1::myFunction();
L’URI funge da stringa di identificazione univoca per lo spazio dei nomi. Se viene omesso,
come nell’esempio seguente, il compilatore crea al suo posto una stringa di identificazione
univoca interna, alla quale non è possibile accedere.
namespace flash_proxy;
Una volta definito uno spazio dei nomi, con o senza URI, non è possibile ridefinirlo
all’interno della stessa area di validità. Un eventuale tentativo in questo senso produce un
errore del compilatore.
Se uno spazio dei nomi viene definito all’interno di un pacchetto o di una classe, potrebbe
non essere visibile per il codice esterno a tale pacchetto o classe, a meno che non venga
utilizzato lo specificatore di controllo accesso appropriato. Ad esempio, nel codice seguente lo
spazio dei nomi flash_proxy è definito all’interno del pacchetto flash.utils. Nell’esempio,
l’assenza di uno specificatore di controllo accesso fa sì che lo spazio dei nomi flash_proxy sia
visibile solo al codice che si trova nel pacchetto flash.utils e invisibile a tutto il codice esterno a
tale pacchetto:
package flash.utils
{
namespace flash_proxy;
}
È possibile aprire più spazi dei nomi nello stesso momento. Quando si utilizza la direttiva use
namespace, lo spazio dei nomi rimane aperto nell’intero blocco di codice in cui è stato aperto.
Non esiste un modo per chiudere esplicitamente uno spazio dei nomi.
La presenza contemporanea di due o più spazi dei nomi aperti, tuttavia, aumenta la
probabilità di conflitti tra nomi. Se si preferisce non aprire uno spazio dei nomi, è possibile
evitare di usare la direttiva use namespace oppure qualificando il nome del metodo o della
proprietà con lo spazio dei nomi e il segno ::. Ad esempio, nel codice seguente il nome
myFunction() viene qualificato con lo spazio dei nomi example1:
example1::myFunction();
Lo spazio dei nomi flash_proxy è definito nel pacchetto flash.utils in un modo simile al
seguente:
package flash.utils
{
public namespace flash_proxy;
}
Lo spazio dei nomi viene applicato ai metodi della classe Proxy come indicato nel seguente
codice estratto da tale classe:
public class Proxy
{
flash_proxy function callProperty(name:*, ... rest):*
flash_proxy function deleteProperty(name:*):Boolean
...
}
Come illustra l’esempio di codice che segue, è necessario prima importare sia la classe Proxy
che lo spazio dei nomi flash_proxy, quindi occorre dichiarare la classe in modo che estenda
la classe Proxy (nonché aggiungere l’attributo dynamic, se il compilatore è in modalità
rigorosa). Se si sostituisce il metodo callProperty(), si deve utilizzare lo spazio dei nomi
flash_proxy.
package
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;
Se si crea un’istanza della classe MyProxy e si chiama un metodo non definito (ad esempio il
metodo testing() chiamato nell’esempio che segue), l’oggetto Proxy intercetta la chiamata al
metodo ed esegue le istruzioni contenute nel metodo callProperty() sostituito (in questo
caso, una semplice istruzione trace()).
var mySample:MyProxy = new MyProxy();
mySample.testing(); // chiamata di metodo intercettata: testing
L’inclusione dei metodi della classe Proxy all’interno dello spazio dei nomi flash_proxy
presenta due vantaggi. Innanzi tutto, la presenza di uno spazio dei nomi separato riduce la
quantità di elementi nell’interfaccia pubblica di qualunque classe che estende la classe Proxy.
(Vi sono circa una dozzina di metodi nella classe Proxy che possono essere sostituiti, nessuno
dei quali è progettato per essere chiamato direttamente. Includerli tutti nello spazio dei nomi
pubblico potrebbe creare confusione.) In secondo luogo, l’uso dello spazio dei nomi
flash_proxy permette di evitare conflitti tra i nomi qualora la sottoclasse Proxy contenga
nomi di metodi di istanze che corrispondono a nomi di metodi della classe Proxy. Ad esempio,
si supponga che uno dei metodi sia denominato callProperty(). Il codice seguente è valido
perché la versione personalizzata del metodo callProperty() si trova in uno spazio dei nomi
diverso:
dynamic class MyProxy extends Proxy
{
public function callProperty() {}
flash_proxy override function callProperty(name:*, ...rest):*
{
trace("method call intercepted: " + name);
}
}
Gli spazi dei nomi sono utili anche quando si desidera fornire accesso a metodi e proprietà in
un modo che non sarebbe possibile con i quattro specificatori di controllo accesso (public,
private, internal e protected). Ad esempio, se si hanno vari metodi di utilità sparsi in
diversi pacchetti e si desidera renderli disponibili a tutti i pacchetti senza tuttavia renderli
pubblici, è possibile creare un nuovo spazio dei nomi e utilizzarlo come specificatore di
controllo accesso personalizzato.
L’esempio seguente utilizza uno spazio dei nomi definito dall’utente per raggruppare due
funzioni che si trovano in pacchetti differenti. Grazie a questa operazione, è possibile rendere
visibili entrambe le funzioni a una classe o a un pacchetto tramite una singola istruzione use
namespace.
Il secondo e il terzo file, Utility.as e Helper.as, definiscono le classi che contengono i metodi
da rendere disponibili agli altri pacchetti. Poiché la classe Utility è nel pacchetto
example.alpha, il file deve essere inserito in una cartella denominata alpha a sua volta
contenuta nella cartella example. Allo stesso modo, la classe Helper si trova nel pacchetto
example.alpha e il file corrispondente deve essere inserito nella sottocartella beta della cartella
example. Entrambi i pacchetti, example.alpha e example.beta, devono importare lo spazio dei
nomi per poterlo utilizzare.
// Utility.as nella cartella example/alpha
package example.alpha
{
import example.myInternal;
Utility.someTask();
Utility.someTask();
trace(Utility.taskCounter); // 2
Helper.someTask();
trace(Helper.lastCalled); // [ultima chiamata di someTask()]
}
}
}
Se si omette l’istruzione var quando si dichiara una variabile, viene generato un errore del
compilatore in modalità rigorosa e un errore runtime in modalità standard. Ad esempio, la
riga di codice seguente genera un errore se la variabile i non è stata definita in precedenza:
i; // errore se i non è stata definita in precedenza
L’associazione di una variabile a un tipo di dati deve essere effettuata al momento di dichiarare
la variabile. La dichiarazione di una variabile senza indicazione del tipo è consentita ma genera
un’avvertenza del compilatore in modalità rigorosa. Per designare il tipo di una variabile, si
aggiunge al nome un carattere di due punti (:) seguito dal tipo. Ad esempio, il codice seguente
dichiara una variabile denominata i del tipo int:
var i:int;
Può risultare più pratico assegnare un valore a una variabile nel momento in cui viene
dichiarata, come nell’esempio seguente:
var i:int = 20;
Questa tecnica viene comunemente utilizzata non solo quando si assegnano valori di base
come numeri interi e stringhe, ma anche quando si un crea un array o un’istanza di una classe.
L’esempio seguente mostra un array che viene dichiarato e al quale viene assegnato un valore
nella stessa riga di codice.
var numArray:Array = ["zero", "one", "two"];
Un’istanza di una classe può essere creata utilizzando l’operatore new. L’esempio seguente crea
un’istanza della classe CustomClass e assegna alla variabile customItem un riferimento alla
nuova istanza creata:
var customItem:CustomClass = new CustomClass();
È anche possibile assegnare valori a ciascuna delle variabili nella stessa riga di codice.
Ad esempio, il codice seguente dichiara tre variabili (a, b e c) e assegna un valore a ciascuna:
var a:int = 10, b:int = 20, c:int = 30;
L’uso dell’operatore virgola per raggruppare le dichiarazioni di variabili nella stessa istruzione
può tuttavia ridurre la leggibilità del codice.
Una variabile locale viene dichiarata all’interno di una definizione di funzione. L’area di codice
più piccola per la quale è possibile definire una variabile locale è una definizione di funzione.
Una variabile locale dichiarata all’interno di una funzione esiste solo in tale funzione. Se, ad
esempio, si dichiara una variabile denominata str2 all’interno di una funzione denominata
localScope(), tale variabile non è disponibile all’esterno della funzione.
function localScope()
{
var strLocal:String = "local";
}
localScope();
trace(strLocal); // Errore perché strLocal non è definita a livello globale
Variabili 89
Se la variabile locale è già stata dichiarata con lo stesso nome come variabile globale, la
definizione locale ha la precedenza sulla definizione globale all’interno dell’area di validità
della variabile locale. La variabile globale rimane valida all’esterno della funzione. Il codice
seguente, ad esempio, crea una variabile globale di tipo String denominata str1, quindi crea
una variabile locale con lo stesso nome all’interno della funzione scopeTest(). L’istruzione
trace all’interno della funzione genera il valore locale della variabile, ma all’esterno della
funzione genera il valore globale della variabile.
var str1:String = "Global";
function scopeTest ()
{
var str1:String = "Local";
trace(str1); // Variabile locale
}
scopeTest();
trace(str1); // Variabile globale
La variabili ActionScript, a differenza delle variabili C++ e Java, non possono avere un’area di
validità a livello di blocco. Un blocco di codice è qualunque gruppo di istruzioni compreso tra
una parentesi graffa di apertura ( { ) e una di chiusura ( } ). In alcuni linguaggi di
programmazione, come C++ e Java, le variabili dichiarate in un blocco di codice non sono
disponibili all’esterno del blocco. Questa restrizione viene definita “area di validità a livello di
blocco” e non esiste in ActionScript. Una variabile dichiarata all’interno di un blocco di codice
è disponibile non solo in tale blocco ma anche nelle altre parti della funzione alla quale esso
appartiene. Ad esempio, la funzione seguente contiene variabili definite in vari blocchi di
codice, ciascuna delle quali è disponibile nell’intera funzione.
function blockTest (testArray:Array)
{
var numElements:int = testArray.length;
if (numElements > 0)
{
var elemStr:String = "Element #";
for (var i:int = 0; i < numElements; i++)
{
var valueStr:String = i + ": " + testArray[i];
trace(elemStr + valueStr);
}
trace(elemStr, valueStr, i); // Tutte ancora definite
}
trace(elemStr, valueStr, i); // Tutte definite se numElements > 0
}
Il compilatore tuttavia non esegue l’hoisting per le istruzioni di assegnazione, motivo per cui
l’istruzione iniziale trace() di num produce NaN (not a number), che è il valore predefinito
per le variabili del tipo di dati Number. Pertanto, è possibile assegnare valori alle variabili
anche prima che siano dichiarate, come nell’esempio seguente:
num = 5;
trace(num); // 5
var num:Number = 10;
trace(num); // 10
Valori predefiniti
Per valore predefinito si intende il valore che una variabile contiene prima che ne venga
impostato il valore. Una variabile viene inizializzata quando se ne imposta il valore per la
prima volta. Se si dichiara una variabile ma non se ne imposta il valore, tale variabile rimane
non inizializzata. Il valore di una variabile non inizializzata dipende dal suo tipo di dati.
La tabella seguente descrive i valori predefiniti delle variabili, organizzati per tipo di dati:
int 0
Number NaN
Object null
String null
uint 0
Per le variabili di tipo Number, il valore predefinito è NaN (not a number), che è un valore
speciale definito dallo standard IEEE-754 per indicare un valore che non rappresenta un
numero.
Variabili 91
Se si dichiara una variabile senza dichiararne il tipo di dati, viene applicato il tipo predefinito *,
che indica che la variabile è priva di tipo. Inoltre, se una variabile senza tipo non viene
inizializzata con un valore, il valore predefinito è undefined.
Per i tipi di dati diversi da Boolean, Number, int e uint, il valore predefinito di qualunque
variabile non inizializzata è null, sia per le classi definite dall’API di Flash Player che per
quelle personalizzate definite dall’utente.
Il valore null non è valido per le variabili di tipo Boolean, Number, int o uint. Se si tenta di
assegnarlo a una di queste variabili, viene convertito nel valore predefinito per il tipo di dati
corrispondente. È invece possibile assegnare il valore null alle variabili di tipo Object. Se si
tenta di assegnare il valore undefined a una variabile Object, il valore viene convertito
in null.
Per le variabili di tipo Number esiste una funzione speciale di primo livello denominata
isNaN(), che restituisce il valore booleano true se la variabile non è un numero oppure
false in caso contrario.
Tipi di dati
Un tipo di dati definisce un set di valori. Ad esempio, il tipo di dati Boolean comprende
esattamente due valori: true e false. Oltre a Boolean, ActionScript 3.0 definisce vari altri
tipi di dati di uso comune, come String, Number e Array. È inoltre possibile creare tipi di dati
personalizzati utilizzando le classi o le interfacce per definire un set di valori specifici.
In ActionScript 3.0 tutti i valori, di base o complessi, sono oggetti.
Un valore di base appartiene a uno dei seguenti tipi di dati: Boolean, int, Number, String e
uint. I valori di base solitamente consentono di lavorare con maggiore rapidità rispetto a
quando si utilizzano valori complessi, perché ActionScript memorizza i valori di base con un
metodo speciale che permette di ottimizzare la memoria e la velocità di elaborazione.
NO T A
Un valore complesso è qualunque valore diverso da un valore di base. I tipi di dati che
definiscono set di valori complessi includono Array, Date, Error, Function RegExp, XML e
XMLList.
Tutti i tipi di dati di base e complessi elencati sopra sono definiti dalle classi di base di
ActionScript 3.0. Tali classi consentono di creare oggetti utilizzando valori letterali anziché
l’operatore new. Ad esempio, è possibile creare un array specificando un valore letterale oppure
la funzione di costruzione della classe Array, come nell’esempio seguente:
var someArray:Array = [1, 2, 3]; // Valore letterale
var someArray:Array = new Array(1,2,3); // Funzione di costruzione Array
Tipi di dati 93
Verifica del tipo in fase di compilazione
La verifica del tipo in fase di compilazione è spesso preferita nei progetti di grandi dimensioni
perché, con il crescere delle dimensioni del progetto, la flessibilità dei tipi di dati perde
generalmente importanza a favore della possibilità di rilevare tutti gli errori di tipo con la
massima tempestività. È per questo motivo che, per impostazione predefinita, il compilatore
ActionScript in Adobe Flash CS3 Professional e in Adobe Flex Builder 2 è configurato per
funzionare in modalità rigorosa.
Per eseguire la verifica del tipo in fase di compilazione, il compilatore deve conoscere il tipo di
dati delle variabili o delle espressioni contenute nel codice. Per dichiarare esplicitamente il tipo
di dati di una variabile, aggiungere al nome della variabile l’operatore due punti (:) seguito dal
tipo di dati come suffisso. Per associare un tipo di dati a un parametro, utilizzare l’operatore
due punti seguito dal tipo di dati. Ad esempio, il codice seguente aggiunge il tipo di dati al
parametro xParam e dichiara una variabile myParam con un tipo di dati esplicito:
function runtimeTest(xParam:String)
{
trace(xParam);
}
var myParam:String = “hello”;
runtimeTest(myParam);
Tipi di dati 95
In determinati casi può essere generato un errore runtime di tipo anche in modalità rigorosa.
Questa situazione può verificarsi quando, pur essendo attiva la modalità rigorosa, si sceglie di
non eseguire la verifica del tipo in fase di compilazione specificando una variabile senza tipo.
L’uso di una variabile senza tipo non elimina la verifica del tipo, bensì la rimanda alla fase di
runtime. Ad esempio, se la variabile myNum di cui all’esempio precedente non ha un tipo di
dati dichiarato, il compilatore non è in grado di rilevare la mancata corrispondenza del tipo
ma Flash Player genera un errore runtime perché esegue un confronto tra il valore runtime di
myNum, che è impostato su 3 dall’istruzione di assegnazione, e il tipo di dati di xParam, che
è Array.
function typeTest(xParam:Array)
{
trace(xParam);
}
var myNum = 3;
typeTest(myNum);
// Errore runtime in ActionScript 3.0
La verifica in fase di runtime consente anche un uso più flessibile dell’ereditarietà rispetto a
quella in fase di compilazione. Rimandando la verifica del tipo alla fase di runtime, la
modalità standard permette di fare riferimento alle proprietà di una sottoclasse anche se si
esegue un upcast, ovvero si utilizza una classe di base per dichiarare il tipo di un’istanza di
classe ma una sottoclasse per creare l’istanza vera e propria. Ad esempio, è possibile creare una
classe denominata ClassBase che può essere estesa (non è possibile estendere le classi con
attributo final):
class ClassBase
{
}
L’operatore is
L’operatore is, introdotto in ActionScript 3.0, consente di verificare se una variabile o
un’espressione è un membro di un determinato tipo di dati. Nelle versioni precedenti di
ActionScript, la stessa funzionalità era fornita dall’operatore instanceof, che tuttavia in
ActionScript 3.0 non va utilizzato per verificare l’appartenenza a un tipo di dati. È necessario
utilizzare l’operatore is anziché instanceof per eseguire la verifica manuale del tipo, perché
l’espressione x instanceof y si limita a controllare se nella catena di prototipi di x è presente
y (in ActionScript 3.0, la catena di prototipi non fornisce un quadro completo della gerarchia
di ereditarietà).
L’operatore is invece esamina la gerarchia di ereditarietà effettiva e consente di verificare non
solo se un oggetto è un’istanza di una particolare classe, ma anche se è un’istanza di una classe
che implementa una particolare interfaccia. L’esempio seguente crea un’istanza della classe
Sprite denominata mySprite e utilizza l’operatore is per verificare se mySprite è un’istanza
delle classi Sprite e DisplayObject e se implementa l’interfaccia IEventDispatcher:
var mySprite:Sprite = new Sprite();
trace(mySprite is Sprite); // true
trace(mySprite is DisplayObject); // true
trace(mySprite is IEventDispatcher); // true
Tipi di dati 97
Il codice dell’esempio seguente esegue gli stessi controlli di quello precedente, ma con
l’operatore instanceof al posto di is. L’operatore instanceof identifica correttamente
mySprite come istanza di Sprite o DisplayObject, ma restituisce false quando viene
utilizzato per verificare se mySprite implementa l’interfaccia IEventDispatcher.
trace(mySprite instanceof Sprite); // true
trace(mySprite instanceof DisplayObject); // true
trace(mySprite instanceof IEventDispatcher); // false
L’operatore as
Anche l’operatore as, introdotto in ActionScript 3.0, consente di verificare se un’espressione è
un membro di un determinato tipo di dati. A differenza di is, tuttavia, as non restituisce un
valore booleano, bensì il valore dell’espressione (invece di true) oppure null (invece di
false). L’esempio seguente mostra il risultato che si ottiene utilizzando l’operatore as anziché
is per controllare semplicemente se un’istanza Sprite è membro dei tipi di dati
DisplayObject, IEventDispatcher e Number.
var mySprite:Sprite = new Sprite();
trace(mySprite as Sprite); // [oggetto Sprite]
trace(mySprite as DisplayObject); // [oggetto Sprite]
trace(mySprite as IEventDispatcher); // [oggetto Sprite]
trace(mySprite as Number); // null
Quando si usa l’operatore as, l’operando sulla destra deve essere un tipo di dati. Un eventuale
tentativo di utilizzare un’espressione diversa da un tipo di dati come operando sulla destra
produrrebbe un errore.
Classi dinamiche
Una classe dinamica definisce un oggetto che può essere alterato in fase di runtime
aggiungendo o modificandone le proprietà e i metodi. Un classe non dinamica, ad esempio la
classe String, si definisce chiusa (sealed in inglese). Non è possibile aggiungere proprietà o
metodi a una classe chiusa in runtime.
Per creare una classe dinamica si utilizza l’attributo dynamic nella relativa dichiarazione.
Ad esempio, il codice seguente crea una classe dinamica denominata Protean:
dynamic class Protean
{
private var privateGreeting:String = "hi";
public var publicGreeting:String = "hello";
function Protean()
{
trace("Protean instance created");
}
}
Le proprietà aggiunte a un’istanza di una classe dinamica sono entità runtime, quindi le
verifiche di qualsiasi tipo vengono eseguite in fase di runtime. Non è possibile aggiungere
un’annotazione di tipo a una proprietà creata in questo modo.
È anche possibile aggiungere un metodo all’istanza myProtean definendo una funzione e
associandola a una proprietà dell’istanza myProtean. Il codice seguente sposta l’istruzione
trace in un metodo denominato traceProtean():
var myProtean:Protean = new Protean();
myProtean.aString = "testing";
myProtean.aNumber = 3;
myProtean.traceProtean = function ()
{
trace(this.aString, this.aNumber);
};
myProtean.traceProtean(); // testing 3
I metodi creati in questo modo, tuttavia, non hanno accesso a eventuali proprietà o metodi
privati della classe Protean. Inoltre, anche i riferimenti a proprietà o metodi pubblici della
classe Protean devono essere qualificati con la parola chiave this o con il nome della classe.
Nell’esempio seguente, il metodo traceProtean() tenta di accedere alle variabili private e
pubbliche della classe Protean.
myProtean.traceProtean = function ()
{
trace(myProtean.privateGreeting); // undefined
trace(myProtean.publicGreeting); // hello
};
myProtean.traceProtean();
Tipi di dati 99
Descrizione dei tipi di dati
I tipi di dati di base sono Boolean, int, Null, Number, String, uint e void. Le classi
ActionScript di base definiscono inoltre i seguenti tipi di dati complessi: Object, Array, Date,
Error, Function, RegExp, XML e XMLList.
Il risultato della divisione per 0 è NaN solo se anche il divisore è 0. La divisione per 0 dà il
risultato infinito se il dividendo è positivo oppure -infinito se è negativo.
Solo le variabili senza tipo possono contenere il valore undefined. Se si tenta di assegnare il
valore undefined a una variabile che appartiene a un tipo di dati, Flash Player converte il
valore undefined nel valore predefinito del tipo di dati in questione. Per le istanze del tipo di
dati Object, il valore predefinito è null. Pertanto, se si tenta di assegnare undefined a
un’istanza Object, Flash Player converte il valore undefined in null.
Conversione implicita
La conversione implicita viene eseguita in fase di runtime in una serie di casi:
■ Nelle istruzioni di assegnazione
■ Quando i valori vengono passati come argomenti di funzioni
■ Quando i valori vengono restituiti da funzioni
■ Nelle espressioni che utilizzano determinati operatori, ad esempio l’operatore di
addizione (+)
Per i tipi definiti dall’utente, la conversione implicita ha luogo quando il valore da convertire è
un’istanza della classe di destinazione o di una classe derivata da essa. Se una conversione
implicita ha esito negativo, viene generato un errore. Ad esempio, il codice seguente contiene
una conversione implicita corretta e una con esito negativo:
class A {}
class B extends A {}
Conversione esplicita
È utile ricorrere alla conversione esplicita (detta anche inserimento o casting) quando si
compila il codice in modalità rigorosa, in particolare quando si vuole evitare che una mancata
corrispondenza di tipo generi un errore in fase di compilazione. Questa situazione può
verificarsi quando si ha la certezza che i valori saranno convertiti correttamente in fase di
runtime mediante l’assegnazione forzata. Ad esempio, quando si utilizzano i dati ricevuti da
un form, si può scegliere di ricorrere all’assegnazione forzata per convertire determinati valori
di stringa in valori numerici. Il codice seguente genera un errore di compilazione anche se, in
modalità standard, verrebbe eseguito senza problemi.
var quantityField:String = "3";
var quantity:int = quantityField; // Errore di compilazione in modalità
// rigorosa
I valori stringa che contengono caratteri non numerici restituiscono 0 se vengono convertiti
con int() o uint() oppure NaN se convertiti con Number(). Il processo di conversione ignora
lo spazio vuoto all’inizio e alla fine, ma restituisce 0 o NaN se una stringa contiene uno spazio
vuoto tra due numeri.
trace(uint("5a")); // 0
trace(uint("ten")); // 0
trace(uint("17 63")); // 0
In ActionScript 3.0, la funzione Number() non supporta più gli ottali, ovvero i numeri a base
8. Se si passa una stringa con uno zero iniziale alla funzione Number() di ActionScript 2.0, il
numero viene interpretato come ottale e convertito nell’equivalente decimale. Lo stesso non
vale per la funzione Number() di ActionScript 3.0, che invece ignora lo zero iniziale.
Ad esempio, il codice seguente genera un output diverso se viene compilato con versioni
differenti di ActionScript:
trace(Number("044"));
// ActionScript 3.0 44
// ActionScript 2.0 36
La tabella che segue riepiloga i risultati dell’inserimento nei tipi Number, int o uint da altri
tipi di dati.
L’output dell’esempio mostra che dei tre numeri solo 0 restituisce il valore false:
Boolean(-1) is true
Boolean(0) is false
Boolean(1) is true
L’inserimento di un valore String nel tipo Boolean restituisce false se la stringa è null o
vuota ("") e true in tutti gli altri casi.
var str1:String; // La stringa non inizializzata è null.
trace(Boolean(str1)); // false
L’inserimento di un’istanza della classe Object nel tipo Boolean restituisce false se l’istanza è
null e true in tutti gli altri casi:
var myObj:Object; // L’oggetto non inizializzato è null.
trace(Boolean(myObj)); // false
La tabella che segue riepiloga i risultati dell’inserimento nel tipo Boolean da altri tipi di dati.
null false
Number, int o uint false se il valore è NaN o 0; true negli altri casi.
La tabella che segue riepiloga i risultati dell’inserimento nel tipo String da altri tipi di dati.
Sintassi
La sintassi di un linguaggio definisce una serie di regole che devono essere rispettate quando si
scrive codice eseguibile.
Mediante la sintassi del punto, è possibile accedere alla proprietà prop1 e al metodo
method1() utilizzando il nome di istanza creato nel codice seguente:
var myDotEx:DotExample = new DotExample();
myDotEx.prop1 = “hello”;
myDotEx.method1();
Si può ricorrere alla sintassi del punto anche per la definizione dei pacchetti. L’operatore
punto viene utilizzato per fare riferimento ai pacchetti nidificati. Ad esempio, la classe
EventDispatcher si trova in un pacchetto denominato events che è nidificato all’interno del
pacchetto flash. Per fare riferimento al pacchetto events, usare l’espressione seguente:
flash.events
È anche possibile fare riferimento alla classe EventDispatcher mediante l’espressione seguente:
flash.events.EventDispatcher
Valori letterali
Per valore letterale si intende un valore che compare direttamente nel codice. I seguenti esempi
sono valori letterali:
17
"hello"
-3
9.4
null
undefined
true
false
Sintassi 111
I valori letterali possono essere raggruppati a formare valori letterali composti. I valori letterali
di array sono racchiusi tra parentesi quadre ([]) e utilizzano la virgola per separare gli elementi
dell’array.
Un valore letterale array può essere utilizzato per inizializzare un array. Gli esempi seguenti
mostrano due array inizializzati tramite valori letterali array. È possibile utilizzare l’istruzione
new e passare il valore letterale composto come parametro alla funzione di costruzione della
classe Array, ma è anche possibile assegnare valori letterali direttamente durante la creazione di
istanze delle seguenti classi principali ActionScript: Object, Array, String, Number, int, uint,
XML, XMLList e Boolean.
// Viene utilizzata l’istruzione new
var myStrings:Array = new Array(["alpha", "beta", "gamma"]);
var myNums:Array = new Array([1,2,3,5,8]);
I valori letterali possono essere anche utilizzati per inizializzare un oggetto generico, ovvero
un’istanza della classe Object. I valori letterali oggetto sono racchiusi tra parentesi graffe ({}) e
utilizzano la virgola per separare le proprietà dell’oggetto. Ogni proprietà viene dichiarata con
il carattere di due punti (:) che separa il nome della proprietà dal relativo valore.
È possibile creare un oggetto generico utilizzando l’istruzione new e passando il valore letterale
dell’oggetto come parametro alla funzione di costruzione della classe Object, oppure assegnare
il valore letterale dell’oggetto direttamente all’istanza che si dichiara. L’esempio seguente crea
un nuovo oggetto generico e lo inizializza con tre proprietà (propA, propB e propC), con
valori impostati rispettivamente su 1, 2 e 3:
// Viene utilizzata l’istruzione new
var myObject:Object = new Object({propA:1, propB:2, propC:3});
Per ulteriori informazioni, vedere “Elementi fondamentali delle stringhe” a pagina 217,
“Nozioni di base delle espressioni regolari” a pagina 306 e “Inizializzazione delle variabili di
XML” a pagina 378.
Parentesi
In ActionScript 3.0 le parentesi (()) hanno tre usi possibili. Innanzi tutto, possono essere
utilizzate per cambiare l’ordine delle operazioni all’interno di un’espressione. Le operazioni
raggruppate all’interno di parentesi vengono sempre eseguite per prime. Ad esempio, nel
codice seguente le parentesi sono state utilizzate per cambiare l’ordine delle operazioni:
trace(2 + 3 * 4); // 14
trace( (2 + 3) * 4); // 20
In secondo luogo, è possibile utilizzare le parentesi con l’operatore virgola (,) per valutare una
serie di espressioni e restituire il risultato dell’espressione finale, come nell’esempio seguente:
var a:int = 2;
var b:int = 3;
trace((a++, b++, a+b)); // 7
Infine, è possibile utilizzare le parentesi per passare uno o più parametri a funzioni o metodi,
come nell’esempio seguente, dove viene passato un valore String alla funzione trace():
trace("hello"); // hello
Commenti
Il codice ActionScript 3.0 supporta due tipi di commenti: a riga singola e su più righe. Questi
meccanismi per l’inserimento di commenti sono simili a quelli di C++ e Java. Tutto il testo
contrassegnato come commento viene ignorato dal compilatore.
I commenti a riga singola iniziano con due caratteri di barra (//) e continuano fino alla fine
della riga. Ad esempio, il codice seguente contiene un commento a riga singola:
var someNumber:Number = 3; // Commento a riga singola
Sintassi 113
I commenti su più righe invece iniziano con una barra seguita da un asterisco (/*) e finiscono
con un asterisco seguito da una barra (*/).
/* Questo è un commento multiriga che può occupare
più di una riga di codice. */
if implements import in
instanceof interface internal is
Esiste inoltre un piccolo gruppo di parole chiave, chiamate parole chiave sintattiche, che
possono essere utilizzate come identificatori ma hanno un significato speciale in determinati
contesti. Nella tabella seguente sono elencate tutte le parole chiave sintattiche di
ActionScript 3.0.
override static
virtual volatile
Costanti
ActionScript 3.0 supporta l’istruzione const, che permette di creare una costante. Le costanti
sono proprietà il cui valore è fisso, ovvero non modificabile. È possibile assegnare un valore a
una costante una sola volta, e l’assegnazione deve avvenire in prossimità della dichiarazione
della costante. Ad esempio, se una costante viene dichiarata come membro di una classe, è
possibile assegnare ad essa un valore solo nella dichiarazione stessa oppure nella funzione di
costruzione della classe.
Il codice seguente dichiara due costanti. Alla prima, MINIMUM, viene assegnato un valore
nell’istruzione della dichiarazione, mentre il valore della seconda costante, MAXIMUM, viene
assegnato nella funzione di costruzione.
class A
{
public const MINIMUM:int = 0;
public const MAXIMUM:int;
Sintassi 115
Se si tenta di assegnare un valore iniziale a una costante in qualunque altro modo, viene
generato un errore. Ad esempio, se si imposta il valore iniziale di MAXIMUM all’esterno della
classe, si verifica un errore runtime.
class A
{
public const MINIMUM:int = 0;
public const MAXIMUM:int;
}
L’API di Flash Player definisce un’ampia gamma di costanti utilizzabili dal programmatore.
Per convenzione, le costanti in ActionScript contengono solo lettere maiuscole, con le parole
separate dal carattere di sottolineatura ( _). Ad esempio, la definizione della classe MouseEvent
utilizza questa convenzione di denominazione per le proprie costanti, ciascuna delle quali
rappresenta un evento relativo all’input del mouse:
package flash.events
{
public class MouseEvent extends Event
{
public static const CLICK:String = "click";
public static const DOUBLE_CLICK:String = "doubleClick";
public static const MOUSE_DOWN:String = "mouseDown";
public static const MOUSE_MOVE:String = "mouseMove";
...
}
}
Operatori
Gli operatori sono funzioni speciali che accettano uno o più operandi e restituiscono un
valore. Un operando è un valore (solitamente un valore letterale, una variabile o
un’espressione) che svolge la funzione di input per un operatore. Ad esempio, nel seguente
codice gli operatori di addizione (+) e moltiplicazione (*) sono utilizzati con tre operandi
letterali (2, 3 e 4) per restituire un valore, il quale viene quindi utilizzato dall’operatore di
assegnazione (=) per assegnare il valore restituito, 14, alla variabile sumNumber.
var sumNumber:uint = 2 + 3 * 4; // uint = 14
Operatori 117
In alcune situazioni, nella stessa espressione possono essere presenti due o più operatori con la
stessa priorità. In questi casi, il compilatore utilizza le regole di associatività per determinare
l’operatore da elaborare per primo. Tutti gli operatori binari, ad eccezione degli operatori di
assegnazione, hanno un’associatività da sinistra a destra, ovvero gli operatori a sinistra vengono
elaborati prima di quelli a destra. Gli operatori binari di assegnazione e l’operatore
condizionale (?:) hanno un’associatività da destra a sinistra, ovvero gli operatori a destra
vengono elaborati prima di quelli a sinistra.
Considerare, ad esempio, gli operatori minore di (<) e maggiore di (>) che hanno la stessa
priorità. Se entrambi gli operatori vengono utilizzati nella stessa espressione, l’operatore a
sinistra viene elaborato per primo, perché l’associatività di entrambi è da sinistra a destra.
Le due istruzioni seguenti producono pertanto lo stesso risultato:
trace(3 > 2 < 1); // false
trace((3 > 2) < 1); // false
L’operatore maggiore di viene elaborato per primo e restituisce true, perché l’operando 3 è
maggiore dell’operando 2. Il valore true viene quindi passato all’operatore minore di insieme
all’operando 1. Il codice seguente illustra questo stato intermedio:
trace((true) < 1);
L’operatore minore di converte il valore true nel valore numerico 1 e confronta quest’ultimo
con il secondo operando 1, restituendo il valore false (perché il valore di 1 non è minore di 1).
trace(1 < 1); // false
L’operatore minore di viene elaborato per primo e restituisce il valore false perché l’operando
2 non è minore dell’operando 1. Il valore false viene quindi passato all’operatore maggiore di
insieme all’operando 3. Il codice seguente illustra questo stato intermedio:
trace(3 > (false));
Gruppo Operatori
Primari [] {x:y} () f(x) new x.y x[y] <></> @ :: ..
Moltiplicativi * / %
Additivi + -
OR bit a bit |
OR logico ||
Condizionali ?:
Virgola ,
Operatori primari
Gli operatori primari consentono di creare valori letterali Array e Object, raggruppare
espressioni, chiamare funzioni, creare istanze di classe e accedere alle proprietà.
Tutti gli operatori primari, elencati nella tabella seguente, hanno priorità equivalente.
Gli operatori inclusi nella specifica E4X sono contrassegnati con l’indicazione (E4X).
Operatori 119
Operatore Operazione eseguita
new Chiama una funzione di costruzione
x.y x[y] Accede a una proprietà
<></> Inizializza un oggetto XMLList (E4X)
@ Accede a un attributo (E4X)
:: Qualifica un nome (E4X)
.. Accede a un elemento XML discendente (E4X)
Tutti gli operatori in forma suffissa, elencati nella tabella seguente, hanno priorità equivalente.
Operatori unari
Gli operatori unari accettano un unico operando. Gli operatori di incremento (++) e
decremento (--) di questo gruppo sono operatori in forma prefissa, ovvero vengono utilizzati
prima dell’operando in un’espressione. Gli operatori in forma prefissa sono diversi da quelli in
forma suffissa perché l’operazione di incremento o decremento viene completata prima della
restituzione del valore di tutta l’espressione. Nel codice seguente, ad esempio, il valore
dell’espressione ++xNum viene restituito dopo l’incremento del valore.
var xNum:Number = 0;
trace(++xNum); // 1
trace(xNum); // 1
Operatori moltiplicativi
Gli operatori moltiplicativi accettano due operandi ed eseguono moltiplicazioni, divisioni e
moduli.
Tutti gli operatori moltiplicativi, elencati nella tabella seguente, hanno priorità equivalente.
Operatori additivi
Gli operatori additivi accettano due operandi ed eseguono addizioni o sottrazioni. Tutti gli
operatori additivi, elencati nella tabella seguente, hanno priorità equivalente.
Operatori 121
Operatori di spostamento bit a bit
Gli operatori di spostamento bit a bit accettano due operandi e spostano i bit del primo
operando in base a quanto specificato dal secondo operando. Tutti gli operatori di
spostamento bit a bit, elencati nella tabella seguente, hanno priorità equivalente.
Operatori relazionali
Gli operatori relazionali accettano due operandi, ne confrontano il valore e restituiscono un
valore booleano. Tutti gli operatori relazionali, elencati nella tabella seguente, hanno priorità
equivalente.
Operatori di uguaglianza
Gli operatori di uguaglianza accettano due operandi, ne confrontano il valore e restituiscono
un valore booleano. Tutti gli operatori di uguaglianza, elencati nella tabella seguente, hanno
priorità equivalente.
Operatori logici
Gli operatori logici accettano due operandi e restituiscono un valore booleano. Gli operatori
logici hanno priorità diversa. Nella tabella seguente, gli operatori sono elencati in ordine di
priorità, da maggiore a minore:
Operatore condizionale
L’operatore condizionale è un operatore ternario, ovvero accetta tre operandi. Può essere
utilizzato come metodo rapido per applicare l’istruzione condizionale if...else.
Operatori 123
Operatori di assegnazione
Gli operatori di assegnazione accettano due operandi e assegnano un valore a uno di essi in
base al valore dell’altro operando. Tutti gli operatori di assegnazione, elencati nella tabella
seguente, hanno priorità equivalente.
Istruzioni condizionali
ActionScript 3.0 offre tre istruzioni condizionali di base che possono essere utilizzate per
controllare il flusso del programma.
if..else
L’istruzione condizionale if..else consente di provare una condizione e quindi eseguire un
blocco di codice se la condizione è soddisfatta o un blocco di codice alternativo in caso
contrario. Il codice seguente, ad esempio, verifica se il valore di x è maggiore di 20 e genera
un’istruzione trace() in caso affermativo oppure un’istruzione trace() diversa in caso
negativo.
if..else if
L’istruzione condizionale if..else if permette di provare più di una condizione. Il codice
seguente, ad esempio, non solo controlla se il valore di x è maggiore di 20, ma anche se è negativo:
if (x > 20)
{
trace("x is > 20");
}
else if (x < 0)
{
trace("x is negative");
}
Adobe tuttavia consiglia di includere sempre le parentesi graffe per evitare risultati imprevisti
nel caso che in un secondo momento vengano aggiunte altre istruzioni a un’istruzione
condizionale priva di parentesi graffe. Ad esempio, nel codice seguente il valore di
positiveNums viene incrementato di 1 indipendentemente dal fatto che la condizione
restituisce o meno il valore true:
var x:int;
var positiveNums:int = 0;
if (x > 0)
trace("x is positive");
positiveNums++;
trace(positiveNums); // 1
for
Il ciclo for permette di eseguire iterazioni su una variabile per verificare un intervallo di valori
specifico. A un’istruzione for è necessario fornire tre espressioni: una variabile impostata su
un valore iniziale, un’istruzione condizionale che determina quando il ciclo termina e
un’espressione che cambia il valore della variabile a ogni ciclo. Il codice seguente, ad esempio,
esegue cinque iterazioni. Il valore della variabile i inizia a 0 e termina a 4 e l’output è
rappresentato dai numeri da 0 a 4, ciascuno su una riga separata.
var i:int;
for (i = 0; i < 5; i++)
{
trace(i);
}
for..in
Il ciclo for..in esegue un’iterazione sulle proprietà di un oggetto o sugli elementi di un array.
È possibile, ad esempio, ricorrere a un ciclo for...in per eseguire iterazioni sulle proprietà di
un oggetto generico (le proprietà degli oggetti non vengono ordinate in base a criteri
particolari, ma inserite in ordine casuale):
var myObj:Object = {x:20, y:30};
for (var i:String in myObj)
{
trace(i + ": " + myObj[i]);
}
// output:
// x: 20
// y: 30
for each..in
Il ciclo for each..in esegue un’iterazione sulle voci di una raccolta, che possono essere tag
contenuti in un oggetto XML o XMLList, i valori delle proprietà di un oggetto o gli elementi
di un array. Ad esempio, come illustra il codice seguente, è possibile utilizzare un ciclo for
each..in per eseguire un’iterazione sulle proprietà di un oggetto generico, tuttavia, a
differenza di quanto avviene con il ciclo for..in, la variabile di iterazione di un ciclo for
each..in contiene il valore della proprietà anziché il suo nome:
var myObj:Object = {x:20, y:30};
for each (var num in myObj)
{
trace(num);
}
// output:
// 20
// 30
È possibile eseguire l’iterazione su un oggetto XML o XMLList, come mostra l’esempio
seguente:
var myXML:XML = <users>
<fname>Jane</fname>
<fname>Susan</fname>
<fname>John</fname>
</users>;
Non è invece possibile eseguire iterazioni sulle proprietà degli oggetti che sono istanze di classi
chiuse. Nel caso di classi dinamiche, non è possibile eseguire l’iterazione sulle proprietà fisse,
ovvero le proprietà definite nella definizione della classe.
while
Il ciclo while è come un’istruzione if che viene ripetuta fintanto che la condizione è true.
Ad esempio, il codice seguente produce lo stesso output dell’esempio di ciclo for:
var i:int = 0;
while (i < 5)
{
trace(i);
i++;
}
Il ciclo while presenta uno svantaggio rispetto al ciclo for: è più facile scrivere cicli infiniti.
A differenza del ciclo for, l’esempio di codice del ciclo while viene compilato anche se si
omette l’espressione che incrementa la variabile del contatore. Senza l’espressione che
incrementa i, il ciclo diventa infinito.
do..while
Il ciclo do..while è un ciclo while che garantisce che il blocco di codice venga eseguito
almeno una volta, perché la condizione viene verificata dopo l’esecuzione del blocco di codice.
Il codice seguente mostra un esempio semplice di un ciclo do..while che genera un output
anche se la condizione non è soddisfatta:
var i:int = 5;
do
{
trace(i);
i++;
} while (i < 5);
// output: 5
Chiamate di funzione
È possibile chiamare una funzione specificando il relativo identificatore seguito dall’operatore
parentesi (()). L’operatore parentesi ha il compito di racchiudere gli eventuali parametri che si
desidera inviare alla funzione. Ad esempio, la funzione trace(), che è una funzione di primo
livello nell’API di Flash Player, è utilizzata spessissimo in questo manuale:
trace(“Use trace to help debug your script”);
Se si chiama una funzione senza parametri, è necessario includere una coppia di parentesi
vuote. Ad esempio, è possibile utilizzare il metodo Math.random(), che non accetta
parametri, per generare un numero casuale:
var randomNum:Number = Math.random();
Istruzioni di funzione
Le istruzioni di funzione sono la tecnica preferita per definire le funzioni in modalità rigorosa.
Un’istruzione di funzione inizia con la parola chiave function, seguita da:
■ Il nome della funzione
■ I parametri, separati da virgole e racchiusi tra parentesi
■ Il corpo della funzione, ovvero il codice ActionScript da eseguire quando la funzione viene
chiamata, racchiuso tra parentesi graffe
Ad esempio, il codice seguente crea una funzione che definisce un parametro, quindi chiama
la funzione utilizzando la stringa "hello" come valore del parametro:
function traceParameter(aParam:String)
{
trace(aParam);
}
traceParameter("hello"); // hello
Espressioni di funzione
Il secondo modo per dichiarare una funzione prevede l’uso di un’istruzione di assegnazione
con un’espressione di funzione, che talvolta viene anche definita letterale di funzione o
funzione anonima. Si tratta di un metodo più verboso, largamente utilizzato nelle versioni
precedenti di ActionScript.
Funzioni 131
Un’istruzione di assegnazione con un’espressione di funzione inizia con la parola chiave var,
seguita da:
■ Il nome della funzione
■ L’operatore due punti (:)
■ La classe Function per indicare il tipo di dati
■ L’operatore di assegnazione (=)
■ La parola chiave function
■ I parametri, separati da virgole e racchiusi tra parentesi
■ Il corpo della funzione, ovvero il codice ActionScript da eseguire quando la funzione viene
chiamata, racchiuso tra parentesi graffe
Ad esempio, il codice seguente dichiara la funzione traceParameter utilizzando
un’espressione di funzione:
var traceParameter:Function = function (aParam:String)
{
trace(aParam);
};
traceParameter("hello"); // hello
Si noti che non occorre specificare un nome di funzione come avviene nelle istruzioni di
funzione. Un’altra importante differenza tra le espressioni di funzione e le istruzioni di
funzione consiste nel fatto che un’espressione di funzione è appunto un’espressione e non
un’istruzione. Ciò significa che un’espressione di funzione, a differenza di un’istruzione di
funzione, non può esistere come elemento autonomo, bensì può essere utilizzata solo
all’interno di un’istruzione, solitamente un’istruzione di assegnazione. L’esempio seguente
mostra un’espressione di funzione assegnata a un elemento array:
var traceArray:Array = new Array();
traceArray[0] = function (aParam:String)
{
trace(aParam);
};
traceArray[0]("hello");
In secondo luogo, è possibile dichiarare l’intera classe come classe dinamica. Sebbene in
questo modo sia possibile chiamare il metodo utilizzando l’operatore punto, la funzionalità
della modalità rigorosa viene parzialmente sacrificata per tutte le istanze di tale classe.
Ad esempio, il compilatore non genera un errore se si tenta di accedere a una proprietà non
definita su un’istanza di una classe dinamica.
Funzioni 133
In determinate circostanze le espressioni di funzione risultano utili. Un caso frequente è quello
delle funzioni che vengono utilizzate una sola volta e quindi eliminate. Un altro utilizzo,
meno comune, riguarda l’associazione di una funzione a una proprietà prototype. Per ulteriori
informazioni, vedere “Oggetto prototype” a pagina 190.
Esistono due sottili differenze tra le istruzioni di funzione e le espressioni di funzione di cui va
tenuto conto quando si sceglie la tecnica da utilizzare. La prima è che un’espressione di
funzione non viene considerata come oggetto indipendente ai fini della gestione della
memoria e del processo di garbage collection. In altre parole, quando si assegna un’espressione
di funzione a un altro oggetto, ad esempio a un elemento di array o una proprietà di un
oggetto, nel codice viene creato semplicemente un riferimento all’espressione di funzione.
Se l’array o l’oggetto al quale è associata l’espressione di funzione esce dall’area di validità o
comunque cessa di essere disponibile, non è più possibile accedere all’espressione. Se l’array o
l’oggetto viene eliminato, la memoria utilizzata dall’espressione di funzione diventa
disponibile per il processo di garbage collection, ovvero può essere riutilizzata per altri scopi.
L’esempio seguente mostra che, se viene eliminata la proprietà alla quale è assegnata
un’espressione di funzione, la funzione non è più disponibile. La classe Test è dinamica e
consente quindi di aggiungere una proprietà denominata functionExp che contiene
un’espressione di funzione. La funzione functionExp() può essere chiamata con l’operatore
punto, ma non è più accessibile dopo l’eliminazione della proprietà functionExp.
dynamic class Test {}
var myTest:Test = new Test();
// espressione di funzione
myTest.functionExp = function () { trace("Function expression") };
myTest.functionExp(); // Espressione di funzione
delete myTest.functionExp;
myTest.functionExp(); // Errore
// Istruzione di funzione
function stateFunc() { trace("Function statement") }
myTest.statement = stateFunc;
myTest.statement(); // Istruzione di funzione
delete myTest.statement;
delete stateFunc; // Nessun effetto
stateFunc(); // Istruzione di funzione
myTest.statement(); // Errore
function statementTest():void
{
trace("statementTest");
}
Le espressioni di funzione non sono disponibili prima della posizione in cui vengono definite,
quindi il codice seguente genera un errore runtime:
expressionTest(); // Errore runtime
Si noti che l’istruzione return termina la funzione, quindi eventuali istruzioni successive a
un’istruzione return non vengono eseguite, come nell’esempio seguente:
function doubleNum(baseNum:int):int {
return (baseNum * 2);
trace("after return"); // Questa istruzione trace non viene eseguita.
}
Funzioni 135
Funzioni nidificate
È possibile nidificare le funzioni, cioè dichiararle all’interno di altre funzioni. Una funzione
nidificata è disponibile solo all’interno della funzione principale in cui è contenuta, a meno
che non venga passato al codice esterno un riferimento alla funzione. Ad esempio, il codice
seguente dichiara due funzioni nidificate all’interno della funzione getNameAndVersion():
function getNameAndVersion():String
{
function getVersion():String
{
return "9";
}
function getProductName():String
{
return "Flash Player";
}
return (getProductName() + " " + getVersion());
}
trace(getNameAndVersion()); // Flash Player 9
Se passate al codice esterno, le funzioni nidificate vengono passate come chiusure di funzione,
vale a dire che la funzione conserva le definizioni che si trovano nell’area di validità nel
momento in cui viene definita. Per ulteriori informazioni, vedere “Chiusure di funzione”
a pagina 144.
Parametri di funzione
ActionScript 3.0 introduce alcune funzionalità relative ai parametri di funzione che
potrebbero sembrare inedite ai programmatori che iniziano a utilizzare questo linguaggio.
Benché l’idea di passare i parametri mediante un valore o un riferimento risulti probabilmente
familiare alla maggior parte dei programmatori, l’oggetto arguments e il parametro ...
(rest) potrebbero invece rappresentare una novità.
Funzioni 137
Tutti gli altri oggetti, ovvero gli oggetti che non appartengono ai tipi di dati primitivi,
vengono sempre passati mediante riferimento, quindi con la possibilità di modificare il valore
della variabile originale. Ad esempio, il codice seguente crea un oggetto denominato objVar
con due proprietà, x e y. L’oggetto viene passato come argomento alla funzione passByRef().
Poiché non appartiene a un tipo di base, l’oggetto non viene semplicemente passato mediante
un riferimento, ma rimane un riferimento. Ciò significa che le modifiche apportate ai
parametri all’interno della funzione avranno effetto sulle proprietà dell’oggetto all’esterno
della funzione.
function passByRef(objParam:Object):void
{
objParam.x++;
objParam.y++;
trace(objParam.x, objParam.y);
}
var objVar:Object = {x:10, y:15};
trace(objVar.x, objVar.y); // 10 15
passByRef(objVar); // 11 16
trace(objVar.x, objVar.y); // 11 16
Il parametro objParam fa riferimento allo stesso oggetto della variabile globale objVar. Come
si può notare nelle istruzioni trace dell’esempio, le modifiche apportate alle proprietà x e y
dell’oggetto objParam vengono applicate anche all’oggetto objVar.
ActionScript 3.0 consente di includere nelle chiamate di funzione più parametri di quelli
definiti nella definizione della funzione; tuttavia, in modalità rigorosa viene generato un
errore del compilatore se il numero di parametri è inferiore a quello dei parametri obbligatori.
È possibile ricorrere alla funzionalità di array dell’oggetto arguments per accedere a
qualunque parametro passato alla funzione, a prescindere che sia o meno definito nella
definizione della funzione. L’esempio seguente utilizza l’array arguments con la proprietà
arguments.length per tracciare tutti i parametri passati alla funzione traceArgArray():
function traceArgArray(x:int):void
{
for (var i:uint = 0; i < arguments.length; i++)
{
trace(arguments[i]);
}
}
traceArgArray(1, 2, 3);
// output:
// 1
// 2
// 3
Funzioni 139
La proprietà arguments.callee viene spesso utilizzata nelle funzioni anonime per creare la
ricorsività e rendere il codice più flessibile. Se il nome di una funzione ricorsiva cambia
durante il ciclo di sviluppo, non occorre modificare la chiamata ricorsiva nel corpo della
funzione se si utilizza arguments.callee al posto del nome della funzione. Nell’espressione
di funzione seguente, la proprietà arguments.callee viene utilizzata per abilitare la
ricorsività:
var factorial:Function = function (x:uint)
{
if(x == 0)
{
return 1;
}
else
{
return (x * arguments.callee(x - 1));
}
}
trace(factorial(5)); // 120
Se si utilizza il parametro ... (rest) nella dichiarazione della funzione, l’oggetto arguments non
è disponibile e per accedere ai parametri è necessario utilizzare i rispettivi nomi che sono stati
dichiarati.
È inoltre importante evitare di utilizzare la stringa "arguments" come nome di parametro
perché impedisce l’uso dell’oggetto arguments. Ad esempio, se la funzione traceArgArray()
viene riscritta con l’aggiunta di un parametro arguments, i riferimenti a arguments nel corpo
della funzione sono relativi al parametro anziché all’oggetto arguments. Il codice seguente
non produce alcun output:
function traceArgArray(x:int, arguments:int):void
{
for (var i:uint = 0; i < arguments.length; i++)
{
trace(arguments[i]);
}
}
traceArgArray(1, 2, 3);
// Nessun output
Nelle versioni precedenti di ActionScript, l’oggetto arguments conteneva anche una proprietà
denominata caller, che era un riferimento alla funzione che chiamava la funzione corrente.
La proprietà caller non è presente in ActionScript 3.0, ma se occorre fare riferimento alla
funzione chiamante, è possibile modificare quest’ultima in modo che passi un parametro
supplementare contenente un riferimento a se stessa.
traceArgArray(1, 2, 3);
// output:
// 1
// 2
// 3
Il parametro ... (rest) può anche essere utilizzato con altri parametri, a condizione che venga
specificato per ultimo. L’esempio seguente modifica la funzione traceArgArray() in modo
tale che il primo parametro, x, sia del tipo int, e il secondo utilizzi il parametro ... (rest).
L’output ignora il primo valore perché il primo parametro non fa più parte dell’array creato
dal parametro ... (rest).
function traceArgArray(x: int, ... args)
{
for (var i:uint = 0; i < args.length; i++)
{
trace(args[i]);
}
}
traceArgArray(1, 2, 3);
// output:
// 2
// 3
Funzioni 141
Funzioni come oggetti
In ActionScript 3.0, le funzioni sono oggetti. Quando si crea una funzione, ciò che viene
creato è in realtà un oggetto che può non solo essere passato come parametro a un’altra
funzione, ma anche disporre di proprietà e metodi.
Le funzioni specificate come argomenti per altre funzioni vengono passate mediante
riferimento e non mediante un valore. Quando si passa una funzione come argomento, si
utilizza solo l’identificatore e si omette l’operatore parentesi usato per chiamare il metodo.
Ad esempio, il codice seguente passa una funzione denominata clickListener() come
argomento al metodo addEventListener():
addEventListener(MouseEvent.CLICK, clickListener);
Anche il metodo Array.sort() definisce un parametro che accetta una funzione. Per un
esempio di funzione di ordinamento personalizzata utilizzata come argomento per la funzione
Array.sort(), vedere “Ordinamento di un array” a pagina 246.
Per quanto possa sembrare strano ai programmatori che iniziano a utilizzare ActionScript, le
funzioni possono avere proprietà e metodi come qualunque altro oggetto. In effetti, ogni
funzione dispone di una proprietà di sola lettura denominata length che memorizza il
numero di parametri definiti per la funzione. Questa proprietà è diversa dalla proprietà
arguments.length, che indica il numero di argomenti passati alla funzione. È bene ricordare
che in ActionScript il numero di argomenti inviati a una funzione può superare quello dei
parametri definiti per la stessa funzione. L’esempio seguente, che viene compilato solo in
modalità standard perché la modalità rigorosa richiede una corrispondenza esatta tra il
numero di argomenti passati e il numero di parametri definiti, mostra la differenza tra le due
proprietà:
function traceLength(x:uint, y:uint):void
{
trace("arguments received: " + arguments.length);
trace("arguments expected: " + traceLength.length);
}
traceLength(3, 5, 7, 11);
/* output:
arguments received: 4
arguments expected: 2 */
function someFunction():void
{
someFunction.counter++;
}
someFunction();
someFunction();
trace(someFunction.counter); // 2
Funzioni 143
La catena dell’area di validità
Ogni volta che inizia l’esecuzione di una funzione, viene creata una serie di oggetti e di
proprietà. Innanzi tutto, viene creato un oggetto speciale chiamato oggetto di attivazione, nel
quale vengono memorizzati i parametri e le eventuali variabili locali o funzioni dichiarate nel
corpo della funzione. Non è possibile accedere direttamente all’oggetto di attivazione perché è
un meccanismo interno. In secondo luogo viene creata una catena dell’area di validità che
contiene un elenco ordinato degli oggetti nei quali Flash Player cerca le dichiarazioni di
identificazione (gli identificatori). Ogni funzione che viene eseguita ha una catena dell’area di
validità che viene memorizzata in una proprietà interna. Nel caso di una funzione nidificata,
la catena dell’area di validità inizia con il proprio oggetto di attivazione, seguito dall’oggetto di
attivazione della relativa funzione principale. La catena prosegue nello stesso modo fino al
raggiungimento dell’oggetto globale, ovvero l’oggetto che viene creato all’inizio di un
programma ActionScript e che contiene tutte le variabili globali e le funzioni.
Chiusure di funzione
Una chiusura di funzione è un oggetto che contiene un’istantanea della funzione e il relativo
ambiente lessicale, il quale comprende tutte le variabili, le proprietà, i metodi e gli oggetti
inclusi nella catena dell’area di validità della funzione, con i rispettivi valori. Le chiusure di
funzione vengono create ogni volta che una funzione viene eseguita indipendentemente da un
oggetto o da una classe. Il fatto che una chiusura di funzione mantenga l’area di validità nella
quale è stata definita produce risultati interessanti quando una funzione viene passata in
un’area di validità diversa come argomento o come valore restituito.
Ad esempio, il codice seguente crea due funzioni: foo(), che restituisce una funzione
nidificata di nome rectArea() che calcola l’area di un rettangolo, e bar(), che chiama foo()
e memorizza la chiusura di funzione restituita in una variabile denominata myProduct. Anche
se la funzione bar() definisce la propria variabile locale x (con valore 2), quando la chiusura
di funzione myProduct() viene chiamata, essa mantiene la variabile x (con valore 40) definita
nella funzione foo(). La funzione bar(), pertanto, restituisce il valore 160 anziché 8.
function foo():Function
{
var x:int = 40;
function rectArea(y:int):int // Chiusura di funzione definita
{
return x * y
}
return rectArea;
}
Funzioni 145
146 Linguaggio e sintassi ActionScript
CAPITOLO 4
Programmazione orientata
agli oggetti con ActionScript
4
In questo capitolo vengono descritti gli elementi di ActionScript che supportano la
programmazione orientata agli oggetti (OOP). Non vengono descritti i principi generali della
programmazione orientata agli oggetti, quali la progettazione degli oggetti, l’astrazione,
l’incapsulamento, l’ereditarietà e il polimorfismo. Il capitolo spiega come è possibile applicare
questi principi utilizzando ActionScript 3.0.
Poiché le basi di ActionScript sono quelle di un linguaggio per la creazione di script, il
supporto della programmazione OOP da parte di ActionScript 3.0 è opzionale.
I programmatori dispongono pertanto di una notevole flessibilità nella scelta dell’approccio
migliore per i progetti, a seconda del livello di complessità e dell’ambito di applicazione.
Per operazioni di portata limitata, l’uso di ActionScript con un paradigma di programmazione
procedurale può risultare del tutto sufficiente. Per i progetti di grandi dimensioni,
l’applicazione dei principi della programmazione a oggetti può rendere il codice più facile da
comprendere, gestire ed estendere.
Sommario
Elementi fondamentali della programmazione orientata agli oggetti . . . . . . . . . . . 148
Classi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
Interfacce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Ereditarietà. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
Argomenti avanzati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
Esempio: GeometricShapes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
147
Elementi fondamentali della
programmazione orientata agli oggetti
Classi
Una classe è una rappresentazione astratta di un oggetto. In una classe sono memorizzate
informazioni sui tipi di dati che un oggetto può contenere e sui comportamenti in base ai
quali un oggetto può funzionare. L’utilità di tale astrazione può non risultare evidente quando
si creano brevi script contenenti solo pochi oggetti che interagiscono tra loro. Tuttavia, con
l’ampliarsi dell’area di validità di un programma e con l’aumentare del numero di oggetti da
gestire, le classi consentono di controllare più accuratamente la creazione degli oggetti e il
modo in cui essi interagiscono.
Fino alla versione di ActionScript 1.0, i programmatori potevano utilizzare gli oggetti
funzione per creare costrutti somiglianti a classi. Con ActionScript 2.0 è stato introdotto il
supporto delle classi con parole chiave quali class ed extends. In ActionScript 3.0, non solo
è previsto il supporto delle parole chiave introdotte in ActionScript 2.0, ma vengono
introdotte anche nuove funzionalità, quale il controllo dell’accesso ottimizzato mediante gli
attributi protected e internal e un migliore controllo dell’ereditarietà grazie all’uso delle
parole chiave final e override.
Se si ha già esperienza nella creazione di classi con linguaggi di programmazione quali Java,
C++ o C#, le procedure di ActionScript risulteranno famigliari. ActionScript utilizza infatti
molte parole chiave e nomi di attributo comuni a tali linguaggi di programmazione, quali
class, extends e public, che verranno illustrati nelle sezioni seguenti.
NO T A
Una modifica significativa della sintassi riguarda la definizione di classi che si trovano
all’interno di un pacchetto. In ActionScript 2.0, se una classe si trovava all’interno di un
pacchetto, il nome del pacchetto doveva essere incluso nella dichiarazione della classe. In
ActionScript 3.0, con l’introduzione dell’istruzione package, il nome del pacchetto deve
essere incluso nella dichiarazione del pacchetto, anziché nella dichiarazione della classe.
Ad esempio, le seguenti dichiarazioni di classe mostrano come la classe BitmapData, che fa
parte del pacchetto flash.display, viene definita ActionScript 2.0 e in ActionScript 3.0:
// ActionScript 2.0
class flash.display.BitmapData {}
// ActionScript 3.0
package flash.display
{
public class BitmapData {}
}
Attributi di classe
ActionScript 3.0 consente di modificare le definizioni delle classi mediante l’impiego di uno
dei seguenti attributi:
Attributo Definizione
dynamic Consente di aggiungere proprietà alle istanze in fase di runtime.
final La classe non può essere estesa da un’altra classe.
internal (valore Visibile ai riferimenti che si trovano all’interno del pacchetto
predefinito) corrente.
public Visibile a tutti i riferimenti.
Classi 151
In tutti questi casi, a eccezione di internal, è necessario includere espressamente l’attributo
per ottenere il comportamento associato. Ad esempio, se durante la definizione di una classe
non si include l’attributo dynamic, non sarà possibile aggiungere proprietà a un’istanza della
classe in fase di runtime. Per assegnare esplicitamente un attributo è necessario collocarlo
all’inizio della definizione della classe, come indicato nel codice seguente:
dynamic class Shape {}
Si tenga presente che nell’elenco non è incluso un attributo denominato abstract. Le classi
astratte non sono infatti supportate in ActionScript 3.0. Si noti inoltre che l’elenco non
contiene attributi denominati private e protected. Tali attributi hanno un significato
unicamente all’interno di una definizione di classe e non possono essere applicati alle classi
stesse. Per fare in modo che una classe non sia pubblicamente visibile al di fuori di un
pacchetto, è necessario inserire la classe in un pacchetto e contrassegnarla con l’attributo
internal. In alternativa, è possibile omettere sia l’attributo internal che public, in tal
modo il compilatore inserirà automaticamente l’attributo internal. Se si desidera che una
classe non sia visibile al di fuori del file di origine che la definisce, collocare la classe alla base
del file di origine, sotto la parentesi graffa che chiude la definizione del pacchetto.
All’interno del corpo di una classe è possibile definire anche uno spazio dei nomi.
Nell’esempio seguente è illustrato come uno spazio dei nomi può essere definito all’interno del
corpo di una classe e utilizzato come attributo di un metodo di tale classe:
public class SampleClass
{
public namespace sampleNamespace;
sampleNamespace function doSomething():void;
}
Classi 153
Attributi delle proprietà di classe
In relazione al modello a oggetti di ActionScript, il termine proprietà si riferisce a un qualsiasi
membro di un una classe, incluse variabili, costanti e metodi. Nella Guida di riferimento al
linguaggio e ai componenti di ActionScript 3.0 il termine viene invece utilizzato in senso più
ristretto per indicare unicamente membri di classi corrispondenti a variabili o definiti
mediante il metodo getter o setter. In ActionScript 3.0 è disponibile una serie di attributi
utilizzabili con qualsiasi proprietà di classe. La tabella seguente riporta tali attributi.
Attributo Definizione
internal (valore Visibile ai riferimenti che si trovano all’interno dello stesso
predefinito) pacchetto.
private Visibile ai riferimenti che si trovano all’interno della stessa classe.
protected Visibile ai riferimenti che si trovano all’interno della stessa classe
e delle classi derivate.
public Visibile a tutti i riferimenti.
static Specifica che una proprietà appartiene alla classe e non alle sue
istanze.
UserDefinedNamespace Nome dello spazio dei nomi personalizzato definito dall’utente.
Nelle classi dichiarate con l’attributo dynamic, i tentativi di accesso a una variabile privata non
provocano errori di runtime. Al contrario, la variabile risulta semplicemente invisibile, di
conseguenza Flash Player restituisce il valore undefined. Un errore in fase di compilazione si
verifica invece se si utilizza un operatore punto in modalità rigorosa. L’esempio seguente è
uguale a quello precedente, con la sola differenza che la classe PrivateExample viene dichiarata
come classe dinamica:
dynamic class PrivateExample
{
private var privVar:String = "private variable";
}
Classi 155
Le classi dinamiche restituiscono in genere il valore undefined, anziché generare un errore, se
un codice esterno alla classe tenta di accedere a una proprietà privata. Nella tabella seguente si
evidenzia che l’errore viene generato unicamente se viene utilizzato l’operatore punto per
accedere a una proprietà privata in modalità rigorosa:
L’attributo protected, nuovo in ActionScript 3.0, rende una proprietà visibile ai chiamanti
della sua stessa classe o di una sottoclasse. In altre parole, una proprietà protetta è disponibile
solo all’interno della propria classe o delle classi che si trovano sotto di essa nella gerarchia di
ereditarietà. Ciò vale sia che la sottoclasse si trovi nello stesso pacchetto o in un pacchetto
differente.
Per chi ha familiarità con ActionScript 2.0, questa funzionalità è simile all’attributo private
di ActionScript 2.0. L’attributo protected di ActionScript 3.0 è simile anche all’attributo
protected di Java, con la sola differenza che la versione per Java consente l’accesso anche ai
chiamanti che si trovano all’interno dello stesso pacchetto. L’attributo protected è utile se si
dispone di una variabile o di un metodo necessario alle sottoclassi, ma che si desidera tenere
nascosto da codice esterno alla catena di ereditarietà.
L’attributo internal, nuovo in ActionScript 3.0, rende una proprietà visibile ai chiamanti
che si trovano all’interno del suo stesso pacchetto. Si tratta dell’attributo predefinito del codice
all’interno di un pacchetto e può essere applicato a qualsiasi proprietà che non presenta alcuno
dei seguenti attributi:
■ public
■ private
■ protected
■ uno spazio dei nomi definito dall’utente
L’attributo internal è simile al controllo dell’accesso predefinito in Java, anche se in Java non
esiste un nome esplicito per tale livello di accesso, che può essere ottenuto solo mediante
l’omissione di un qualsiasi altro modificatore dell’accesso. L’attributo internal di
ActionScript 3.0 consente all’utente di dimostrare esplicitamente l’intenzione di rendere una
proprietà visibile unicamente ai chiamanti che si trovano all’interno del suo stesso pacchetto.
Variabili
Le variabili possono essere dichiarate con le parole chiave var o const. I valori delle variabili
dichiarate con la parola chiave var possono essere modificati più volte durante l’esecuzione di
uno script. Le variabili dichiarate con la parola chiave const sono dette costanti e a esse
possono essere assegnati valori una sola volta. Se si tenta di assegnare un nuovo valore a una
costante inizializzata si verifica un errore. Per ulteriori informazioni, vedere “Costanti”
a pagina 115.
Variabili statiche
Le variabili statiche vengono dichiarate utilizzando una combinazione della parola chiave
static e dell’istruzione var o const. Le variabili statiche che vengono associate a una classe,
anziché all’istanza di una classe, sono utili per memorizzare e condividere informazioni
applicabili a un’intera classe di oggetti. Ad esempio, è appropriato l’impiego di una variabile
statica per registrare quante volte viene creata un’istanza di una determinata classe oppure per
memorizzare il numero massimo di istanze di una classe consentito.
Classi 157
Nell’esempio seguente viene creata una variabile totalCount per registrare il numero di volte
in cui viene creata l’istanza di una classe e una costante MAX_NUM per memorizzare il numero
massimo di istanze consentite. Le variabili totalCount e MAX_NUM sono statiche, in quanto
contengono valori applicabili all’intera classe e non a una sua particolare istanza.
class StaticVars
{
public static var totalCount:int = 0;
public static const MAX_NUM:uint = 16;
}
Il codice esterno alla classe StaticVars e alle sue sottoclassi può fare riferimento alle proprietà
totalCount e MAX_NUM solo attraverso la classe stessa. Ad esempio, il codice seguente
funziona:
trace(StaticVars.totalCount); // output: 0
trace(StaticVars.MAX_NUM); // output: 16
Non è possibile accedere a variabili statiche attraverso un’istanza della classe; il codice seguente
restituisce degli errori:
var myStaticVars:StaticVars = new StaticVars();
trace(myStaticVars.totalCount); // Errore
trace(myStaticVars.MAX_NUM); // Errore
Le variabili dichiarate sia con la parola chiave static che const devono essere inizializzate nel
momento in cui viene dichiarata la costante, come avviene all’interno della classe StaticVars
per MAX_NUM. Non è possibile assegnare un valore a MAX_NUM all’interno della funzione di
costruzione o di un metodo di istanza. Il codice seguente genera un errore in quanto non è un
metodo valido per inizializzare una costante statica:
// !! Errore; impossibile inizializzare una costante in questo modo
class StaticVars2
{
public static const UNIQUESORT:uint;
function initializeStatic():void
{
UNIQUESORT = 16;
}
}
Metodi
I metodi sono funzioni che fanno parte di una definizione di classe. Una volta creata
un’istanza della classe, un metodo viene associato a tale istanza. A differenza delle funzioni
dichiarate all’esterno delle classi, i metodi possono essere utilizzati esclusivamente dall’istanza
alla quale sono associati.
I metodi vengono definiti utilizzando la parola chiave function. È possibile utilizzare una
funzione con istruzione, come nell’esempio seguente:
public function sampleFunction():String {}
Oppure è possibile utilizzare una variabile alla quale viene assegnata un’espressione della
funzione, come nell’esempio seguente:
public var sampleFunction:Function = function () {}
Nella maggior parte dei casi, è consigliabile utilizzare una funzione con istruzione anziché
un’espressione della funzione per le ragioni seguenti:
■ Le funzioni con istruzione sono più concise e più facili da leggere.
■ Le funzioni con istruzione consentono di utilizzare le parole chiave override e final. Per
ulteriori informazioni, vedere “Sostituzione di metodi” a pagina 179.
■ Le funzioni con istruzione consentono di creare un legame più solido tra l’identificatore
(vale a dire, il nome della funzione) e il codice, all’interno del corpo del metodo. Poiché il
valore di una variabile può essere modificato mediante un’istruzione di assegnazione, il
legame tra la variabile e la relativa espressione della funzione può essere sciolto in qualsiasi
momento. Nonostante sia possibile ovviare a questo problema dichiarando la variabile con
la parola chiave const anziché var, tale sistema non è consigliato, in quanto rende il
codice di difficile lettura e impedisce l’uso delle parole chiave override e final.
Classi 159
Un caso in cui è consigliabile l’uso di un’espressione della funzione è quando si decide di
associare una funzione all’oggetto prototype. Per ulteriori informazioni, vedere “Oggetto
prototype” a pagina 190.
I metodi delle funzioni di costruzione possono essere solo pubblici, tuttavia, l’impiego
dell’attributo public è facoltativo. Nelle funzioni di costruzione non è possibile usare nessuno
degli altri specificatori del controllo di accesso, incluso private, protected o internal.
Con i metodi delle funzioni di costruzione non è inoltre possibile utilizzare spazi dei nomi
definiti dall’utente.
Una funzione di costruzione può effettuare una chiamata esplicita alla funzione di costruzione
della sua superclasse diretta mediante l’istruzione super(). Se la funzione di costruzione della
superclasse non viene esplicitamente chiamata, il compilatore inserisce automaticamente una
chiamata prima della prima istruzione nel corpo della funzione di costruzione. Per chiamare i
metodi della superclasse, è inoltre possibile utilizzare il prefisso super come riferimento alla
superclasse. Se si decide di utilizzare sia super() che super nello stesso corpo della funzione
di costruzione, assicurarsi di chiamare prima super(). In caso contrario, il riferimento super
non funzionerà correttamente. La funzione di costruzione super() deve inoltre essere
chiamata prima di eventuali istruzioni throw o return.
Metodi statici
I metodi statici, chiamati anche metodi di classe, sono metodi che vengono dichiarati con la
parola chiave static. I metodi statici, generalmente associati a una classe anziché all’istanza
di una classe, sono utili per incorporare funzionalità relative a qualcosa di diverso dallo stato di
singole istanze. Poiché i metodi statici vengono associati a un’intera classe, è possibile
accedervi solo attraverso la classe stessa e non attraverso un’istanza della classe.
Classi 161
I metodi statici sono utili per incorporare funzioni che non si limitano a modificare lo stato
delle istanze di classe. In altre parole, un metodo si definisce statico se fornisce funzionalità
che non intervengono direttamente sul valore di un’istanza di classe. Ad esempio, la classe
Date presenta un metodo statico denominato parse() che converte una stringa in un
numero. Tale metodo è statico in quanto non modifica una singola istanza della classe.
Il metodo parse() prende invece una stringa che rappresenta un valore data, l’analizza e
restituisce un numero in un formato compatibile con la rappresentazione interna dell’oggetto
Date. Questo metodo non è un metodo di istanza, in quanto non avrebbe senso applicarlo a
un’istanza della classe Date.
Il metodo statico parse() è in contrasto con i metodi di istanza della classe Date, quale
getMonth(). Il metodo getMonth() è un metodo di istanza, in quanto opera direttamente sul
valore recuperando un componente specifico, il mese, di un’istanza Date.
Poiché i metodi statici non sono associati a singole istanze, non è possibile utilizzare le parole
chiave this o super all’interno del corpo di un metodo statico. Sia il riferimento this che
super hanno significato solo nel contesto di un metodo di istanza.
Metodi di istanza
I metodi di istanza sono metodi dichiarati senza la parola chiave static. Questi metodi, che
vengono associati alle istanze di una classe anziché all’intera classe, sono utili per
implementare funzionalità che riguardano singole istanze di una classe. Ad esempio, la classe
Array contiene un metodo di istanza denominato sort() che opera direttamente sulle
istanze Array.
Se il codice esterno alla classe deve fare riferimento alla variabile statica arrayCountTotal
mediante l’oggetto di classe, utilizzando CustomArray.arrayCountTotal, il codice che
risiede nel corpo del metodo getPosition() può fare riferimento direttamente alla variabile
statica arrayCountTotal. Ciò vale anche per le variabili statiche contenute nelle superclassi.
Anche se le proprietà statiche non vengono ereditate in ActionScript 3.0, quelle presenti nelle
superclassi sono nell’area di validità. Ad esempio, la classe Array presenta poche variabili
statiche, una delle quali è una costante denominata DESCENDING. Il codice residente in una
delle sottoclassi di Array può fare riferimento alla costante statica DESCENDING mediante un
semplice identificatore.
public class CustomArray extends Array
{
public function testStatic():void
{
trace(DESCENDING); // output: 2
}
}
Classi 163
Il valore del riferimento this nel corpo di un metodo di istanza è un riferimento all’istanza
alla quale il metodo è associato. Il codice seguente illustra come il riferimento this punti
all’istanza contenente il metodo:
class ThisTest
{
function thisValue():ThisTest
{
return this;
}
}
L’ereditarietà dei metodi di istanza può essere controllata con le parole chiave override e
final. Utilizzare l’attributo override per ridefinire un metodo ereditato e l’attributo final
per impedire alle sottoclassi di sostituire un metodo. Per ulteriori informazioni, vedere
“Sostituzione di metodi” a pagina 179.
Gli utenti della classe GetSet utilizzeranno invece qualcosa che appare come una proprietà
denominata publicAccess, ma che in realtà è una coppia di funzioni get e set che operano
sulla proprietà privata chiamata privateProperty. Nell’esempio seguente viene creata
un’istanza della classe GetSet, quindi viene impostato il valore di privateProperty mediante
l’accessor pubblico denominato publicAccess:
var myGetSet:GetSet = new GetSet();
trace(myGetSet.publicAccess); // output: null
myGetSet.publicAccess = "hello";
trace(myGetSet.publicAccess); // output: hello
Metodi vincolati
Un metodo vincolato, o chiusura di un metodo, è semplicemente un metodo estratto dalla
propria istanza. Tra gli esempi di metodi vincolati vi sono metodi passati come argomenti a
una funzione o restituiti come valori da una funzione. Tra le novità di ActionScript 3.0 vi è un
metodo vincolato simile a una chiusura di funzione, in quanto in grado di conservare il
proprio ambiente lessicale anche se estratto dall’istanza a cui è associato. Tuttavia, la principale
differenza tra un metodo vincolato e una chiusura di funzione è che il riferimento this del
metodo vincolato resta collegato, o vincolato, all’istanza che implementa il metodo. In altre
parole, il riferimento this in un metodo vincolato punta sempre all’oggetto originale cha ha
implementato il metodo. Nelle funzioni di chiusura, il riferimento this è generico, vale a dire
che punta a qualsiasi oggetto associato alla funzione nel momento in cui viene chiamato.
Classi 165
Una corretta comprensione dei metodi vincolati è importante se si utilizza la parola chiave
this. Il richiamo della parola chiave this fornisce un riferimento a un oggetto principale del
metodo. Per la maggior parte dei programmatori ActionScript la parola chiave this fa sempre
riferimento all’oggetto o alla classe che contiene la definizione di un metodo. Senza i metodi
vincolati, tuttavia, ciò non sarebbe sempre possibile. Nelle versioni precedenti di ActionScript,
ad esempio, il riferimento this non era sempre riferito all’istanza che aveva implementato il
metodo. Se in ActionScript 2.0 i metodi vengono estratti da un’istanza, non solo il riferimento
this resta vincolato all’istanza originale, ma le variabili di membro e i metodi della classe
dell’istanza non risultano disponibili. Il problema non esiste in ActionScript 3.0, in quanto i
metodi vincolati vengono automaticamente creati quando un metodo viene passato come
parametro. I metodi vincolati garantiscono che la parola chiave this faccia sempre
riferimento all’oggetto o alla classe nella quale il metodo viene definito.
Il codice seguente definisce una classe denominata ThisTest, contenente un metodo chiamato
foo() che definisce a sua volta il metodo vincolato e un metodo bar() che restituisce il
metodo vincolato. Il codice esterno alla classe crea un’istanza della classe ThisTest, chiama il
metodo bar() e memorizza il valore restituito in una variabile denominata myFunc.
class ThisTest
{
private var num:Number = 3;
function foo():void // metodo vincolato definito
{
trace("foo's this: " + this);
trace("num: " + num);
}
function bar():Function
{
return foo; // metodo vincolato restituito
}
}
Per convenzione, una classe di enumerazione viene dichiarata con l’attributo final in quanto
non vi è necessità di estendere la classe. La classe comprende solo membri statici, di
conseguenza non si potranno creare istanze della classe. Al contrario, è possibile accedere ai
valori di enumerazione direttamente tramite l’oggetto di classe, come illustrato nel seguente
estratto di codice:
var pj:PrintJob = new PrintJob();
if(pj.start())
{
if (pj.orientation == PrintJobOrientation.PORTRAIT)
{
...
}
...
}
Classi 167
Tutte le classi di enumerazione nell’API di Flash Player contengono solo variabili di tipo
String, int o uint. Il vantaggio di utilizzare enumerazioni anziché stringhe di caratteri o valori
numerici è che gli errori tipografici sono più facilmente rilevabili nelle enumerazioni. Se si
digita in modo errato il nome di un’enumerazione, il compilatore di ActionScript genera un
errore. Se si usano valori letterali, il compilatore non rileva gli errori ortografici o l’uso di un
numero errato. Nell’esempio precedente, se il nome della costante di enumerazione non è
corretto, il compilatore genera un errore, come illustrato nell’estratto seguente:
if (pj.orientation == PrintJobOrientation.PORTRAI) // errore del
// compilatore
Una seconda tecnica per la creazione di enumerazioni prevede anch’essa la creazione di una
classe separata con proprietà statiche per l’enumerazione. Ciò che differenzia questa tecnica,
tuttavia, è che le proprietà statiche contengono un’istanza della classe anziché una stringa o un
valore intero. Ad esempio, il seguente codice consente di creare una classe di enumerazione
per i giorni della settimana:
public final class Day
{
public static const MONDAY:Day = new Day();
public static const TUESDAY:Day = new Day();
public static const WEDNESDAY:Day = new Day();
public static const THURSDAY:Day = new Day();
public static const FRIDAY:Day = new Day();
public static const SATURDAY:Day = new Day();
public static const SUNDAY:Day = new Day();
}
È inoltre possibile ottimizzare la classe Day in modo che a ogni giorno della settimana venga
associato un numero intero e fornire un metodo toString() che restituisca una
rappresentazione del giorno sotto forma di stringa. È possibile migliorare in questo modo la
classe Day come esercizio.
Classi 169
Classi delle risorse incorporate
In ActionScript 3.0 vengono impiegate classi speciali, chiamate classi delle risorse incorporate,
per rappresentare risorse incorporate. Una risorsa incorporata è una risorsa, quale un suono,
un’immagine o un carattere, che viene inclusa in un file SWF in fase di compilazione.
L’incorporamento, anziché il caricamento dinamico, di una risorsa ne garantisce la
disponibilità in fase di runtime, ma al costo di un incremento delle dimensioni del file SWF.
Interfacce
Un’interfaccia è una raccolta di dichiarazioni di metodi che consente a oggetti non correlati di
comunicare tra loro. Ad esempio, l’API di Flash Player definisce l’interfaccia
IEventDispatcher, che contiene dichiarazioni di metodi utilizzabili dalle classi per gestire gli
oggetti evento. L’interfaccia IEventDispatcher stabilisce una modalità standard per il passaggio
degli oggetti evento da un oggetto all’altro. Il codice seguente mostra la definizione
dell’interfaccia IEventDispatcher:
public interface IEventDispatcher
{
function addEventListener(type:String, listener:Function,
useCapture:Boolean=false, priority:int=0,
useWeakReference:Boolean = false):void;
function removeEventListener(type:String, listener:Function,
useCapture:Boolean=false):void;
function dispatchEvent(event:Event):Boolean;
function hasEventListener(type:String):Boolean;
function willTrigger(type:String):Boolean;
}
...
}
Interfacce 171
Definizione di un’interfaccia
La struttura della definizione di un’interfaccia è simile a quella della definizione di una classe,
a eccezione del fatto che l’interfaccia può contenere solo metodi e non corpi dei metodi. Le
interfacce inoltre non possono includere variabili o costanti, ma possono incorporare funzioni
getter e setter. Per definire un’interfaccia, utilizzare la parola chiave interface. Ad esempio, la
seguente interfaccia, IExternalizable, fa parte del pacchetto flash.utils dell’API di Flash Player.
L’interfaccia IExternalizable definisce un protocollo per la serializzazione di un oggetto, vale a
dire la conversione di un oggetto in un formato idoneo per la memorizzazione su un
dispositivo o per la trasmissione in rete.
public interface IExternalizable
{
function writeExternal(output:IDataOutput):void;
function readExternal(input:IDataInput):void;
}
interface IBeta
{
function bar():void;
}
Interfacce 173
È disponibile un po’ di flessibilità anche per quanto riguarda i valori di parametro predefiniti.
Una definizione di interfaccia può includere dichiarazioni di funzioni con valori di parametro
predefiniti. Un metodo che implementa una tale dichiarazione di funzione deve avere un
valore di parametro predefinito che sia membro dello stesso tipo di dati del valore specificato
nella definizione di interfaccia, anche se il valore vero e proprio può essere differente.
Ad esempio, il codice seguente definisce un’interfaccia che contiene un metodo con un valore
di parametro predefinito 3:
interface IGamma
{
function doSomething(param:int = 3):void;
}
Il motivo di questa flessibilità sta nel fatto che le regole di implementazione dell’interfaccia
sono state specificamente studiate per garantire la compatibilità dei tipi di dati e per
raggiungere tale obiettivo non è richiesta una corrispondenza dei nomi dei parametri e dei
valori predefiniti.
Ereditarietà
L’ereditarietà è una forma di riutilizzo del codice che consente ai programmatori di sviluppare
nuove classi basate sulle classi esistenti. Le classi esistenti vengono spesso definite classi base o
superclassi, mentre le nuove classi sono generalmente chiamate sottoclassi. Uno dei principali
vantaggi dell’ereditarietà è che consente di riutilizzare il codice di una classe di base, senza
modificare il codice esistente. Inoltre, l’ereditarietà non richiede di modificare il modo in cui
le altre classi interagiscono con la classe di base. Anziché modificare una classe esistente già
ampiamente testata o già in uso, l’impiego dell’ereditarietà consente di trattare tale classe
come un modulo integrato da estendere con proprietà o metodi aggiuntivi. Di conseguenza, la
parola chiave extends viene utilizzata per indicare che una classe eredita da un’altra classe.
Ereditarietà 175
Poiché ogni classe definisce un tipo di dati, l’uso dell’ereditarietà crea una speciale relazione tra
la classe base e la classe che la estende. Una sottoclasse possiede sempre tutte le proprietà della
sua classe base, di conseguenza una qualsiasi istanza di una sottoclasse può sempre essere
sostituita con un’istanza della classe base. Ad esempio, se un metodo definisce un parametro di
tipo Shape, è consentito il passaggio di un argomento di tipo Circle, in quanto Circle è
un’estensione di Shape, come indicato di seguito:
function draw(shapeToDraw:Shape) {}
Se una proprietà viene dichiarata con la parola chiave private, essa risulterà visibile solo nella
classe che la definisce e non verrà ereditata da alcuna delle sottoclassi. Ciò non accadeva nelle
versioni precedenti di ActionScript, dove la parola chiave private si comportava in modo
simile alla parola chiave protected di ActionScript 3.0.
La parola chiave protected indica che una proprietà è visibile non solo all’interno della classe
che la definisce, ma anche in tutte le sue sottoclassi. A differenza della parola chiave
protected del linguaggio di programmazione Java, la parola chiave protected di
ActionScript 3.0 non rende una proprietà visibile a tutte le altre classi dello stesso pacchetto.
In ActionScript 3.0, solo le sottoclassi possono accedere a una proprietà dichiarata con la
parola chiave protected. Inoltre, una proprietà protetta è visibile a una sottoclasse, sia che
questa si trovi nello stesso pacchetto della classe base che in un pacchetto differente.
Per limitare la visibilità di una proprietà al pacchetto nel quale essa è stata definita, utilizzare la
parola chiave internal oppure non utilizzare alcuno specificatore del controllo di accesso.
Lo specificatore del controllo di accesso internal è lo specificatore predefinito che viene
applicato quando non ne viene specificato alcuno. Se una proprietà viene contrassegnata come
internal essa verrà ereditata unicamente dalle sottoclassi che risiedono nello stesso
pacchetto.
Ereditarietà 177
L’esempio seguente mostra come ogni specificatore del controllo di accesso può modificare
l’ereditarietà nell’ambito dei pacchetti. Il codice seguente definisce una classe di applicazione
principale chiamata AccessControl e due altre classi chiamate Base ed Extender. La classe Base
si trova in un pacchetto denominato foo, mentre la classe Extender, che è una sottoclasse della
classe Base, si trova in un pacchetto chiamato bar. La classe AccessControl importa
unicamente la classe Extender e crea un’istanza di Extender che tenta di accedere a una
variabile chiamata str definita nella classe Base. La variabile str è dichiarata come public, di
conseguenza il codice viene compilato ed eseguito come nell’estratto seguente:
// Base.as in una cartella chiamata foo
package foo
{
public class Base
{
public var str:String = "hello"; // modifica public in questa riga
}
}
Sostituzione di metodi
Sostituire un metodo significa ridefinire il comportamento di un metodo ereditato. I metodi
statici non vengono ereditati e non possono essere sostituiti. I metodi di istanza, tuttavia,
vengono ereditati dalle sottoclassi e possono essere sostituiti a condizione che vengano
soddisfatti i seguenti criteri:
■ Il metodo di istanza non deve essere dichiarato con la parola chiave final nella classe
base. Se utilizzata con un metodo di istanza, la parola chiave final indica l’intenzione del
programmatore di impedire alle sottoclassi di sostituire il metodo.
■ Il metodo di istanza non deve essere dichiarato con lo specificatore del controllo di accesso
private nella classe base. Se un metodo viene contrassegnato come private nella classe
base, non è necessario utilizzare la parola chiave override per la definizione di un metodo
con nome identico nella sottoclasse, in quanto il metodo della classe base non risulterà
visibile alla sottoclasse.
Per sostituire un metodo di istanza che soddisfi i criteri di cui sopra, è necessario che nella
definizione del metodo all’interno della sottoclasse venga utilizzata la parola chiave override
e che tale definizione corrisponda alla versione del metodo della superclasse, nei modi indicati
di seguito:
■ Il metodo di sostituzione deve avere lo stesso livello di controllo di accesso del metodo
della classe base. I metodi contrassegnati come interni hanno lo stesso livello di controllo
di accesso dei metodi che non presentano alcuno specificatore del controllo di accesso.
■ Il metodo di sostituzione deve avere lo stesso numero di parametri del metodo della
classe base.
Ereditarietà 179
■ I parametri del metodo di sostituzione devono avere le stesse annotazioni di tipo di dati
dei parametri del metodo della classe base.
■ Il metodo di sostituzione deve avere lo stesso tipo restituito del metodo della classe base.
I nomi dei parametri del metodo di sostituzione, tuttavia, non devono corrispondere ai nomi
dei parametri del metodo della classe base, a condizione che il numero dei parametri e il tipo
di dati di ciascun parametro corrisponda.
Istruzione super
Quando sostituiscono un metodo, i programmatori spesso intendono aggiungere qualcosa al
comportamento del metodo della superclasse da sostituire, anziché rimpiazzare
completamente tale comportamento. Ciò richiede un meccanismo che consenta a un metodo
in una sottoclasse di richiamare la versione di se stesso presente nella superclasse. L’istruzione
super consente tale operazione, in quanto contiene un riferimento all’immediata superclasse.
Nell’esempio seguente viene definita una classe chiamata Base contenente un metodo
chiamato thanks() e una sottoclasse della classe Base denominata Extender che sostituisce il
metodo thanks(). Il metodo Extender.thanks() impiega l’istruzione super per chiamare
Base.thanks().
package {
import flash.display.MovieClip;
public class SuperExample extends MovieClip
{
public function SuperExample()
{
var myExt:Extender = new Extender()
trace(myExt.thanks()); // output: Mahalo nui loa
}
}
}
class Base {
public function thanks():String
{
return "Mahalo";
}
}
Ereditarietà 181
package {
import flash.display.MovieClip;
public class StaticExample extends MovieClip
{
public function StaticExample()
{
var myExt:Extender = new Extender();
trace(myExt.test); // Errore
}
}
}
class Base {
public static var test:String = "static";
}
È tuttavia consentito definire una proprietà di istanza con lo stesso nome della proprietà
statica. Tale proprietà di istanza può essere definita nella stessa classe della proprietà statica o
in una sua sottoclasse. Ad esempio, la classe Base dell’esempio precedente potrebbe avere una
proprietà di istanza denominata test. Il codice seguente viene compilato ed eseguito perché la
proprietà di istanza viene ereditata dalla classe Extender. Il codice verrebbe compilato ed
eseguito anche se la definizione della variabile di istanza test venisse spostata, ma non copiata,
nella classe Extender.
package
{
import flash.display.MovieClip;
public class StaticExample extends MovieClip
{
public function StaticExample()
{
var myExt:Extender = new Extender();
trace(myExt.test); // output: istanza
}
}
}
class Base
{
public static var test:String = "static";
public var test:String = "instance";
}
class Base {
public static var test:String = "static";
}
Se viene definita una proprietà di istanza che impiega lo stesso nome di una proprietà statica
presente nella stessa classe o in una superclasse, la proprietà di istanza ha una precedenza
maggiore nella catena delle aree di validità. La proprietà di istanza prevarica la proprietà
statica, ovvero il valore della proprietà di istanza viene utilizzato al posto del valore della
proprietà statica. Ad esempio, il codice seguente mostra che, se la classe Extender definisce
una variabile di istanza denominata test, l’istruzione trace() impiega il valore della variabile
di istanza anziché quello della variabile statica.
Ereditarietà 183
package
{
import flash.display.MovieClip;
public class StaticExample extends MovieClip
{
public function StaticExample()
{
var myExt:Extender = new Extender();
}
}
}
class Base
{
public static var test:String = "static";
}
Argomenti avanzati
Questa sezione si apre con una breve storia di ActionScript e della programmazione a oggetti e
continua con una discussione sul modello a oggetti di ActionScript 3.0 e su come esso
consenta alla nuova AVM2 (ActionScript Virtual Machine) di funzionare molto più
velocemente rispetto a versioni precedenti di Flash Player che contenevano AVM1.
La classe Shape e la classe Circle sono ora collegate in una relazione di ereditarietà
comunemente conosciuta come catena di prototipi. Il diagramma seguente illustra le varie
relazioni in una catena di prototipi:
Object.prototype
Shape.prototype
Circle.prototype
La classe alla base di ogni catena di prototipi è la classe Object. La classe Object contiene una
proprietà statica denominata Object.prototype che punta all’oggetto prototipo di base di
tutti gli oggetti creati in ActionScript 1.0. L’oggetto successivo nella catena di prototipi di
esempio è l’oggetto Shape. La proprietà Shape.prototype infatti non è mai stata
esplicitamente impostata e contiene ancora un oggetto generico (un’istanza della classe
Object). Il collegamento finale della catena è costituito dalla classe Circle, collegata al suo
prototipo, la classe Shape (la proprietà Circle.prototype contiene un oggetto Shape).
Se si crea un’istanza della classe Circle, come nell’esempio seguente, tale istanza eredita la
catena di prototipi della classe Circle:
// Crea un’istanza della classe Circle.
myCircle = new Circle();
ActionScript 2.0
In ActionScript 2.0 vengono introdotte nuove parole chiave, quali class, extends, public e
private, che consentono di definire le classi in maniera simile ai linguaggi basati sulle classi,
quali Java e C++. È importante tenere presente che il meccanismo di ereditarietà alla base non
è cambiato con il passaggio da ActionScript 1.0 ad ActionScript 2.0. In ActionScript 2.0 è
stato semplicemente aggiunto un nuovo tipo sintassi per la definizione delle classi. La catena
dei prototipi funziona alla stessa maniera in entrambe le versioni del linguaggio.
La nuova sintassi introdotta da ActionScript 2.0, e illustrata nell’estratto seguente, consente di
definire le classi in un modo che molti programmatori trovano più intuitivo:
// classe base
class Shape
{
var visible:Boolean = true;
}
Si tenga inoltre presente che in ActionScript 2.0 sono state introdotte anche le annotazioni di
tipo da utilizzare con la verifica del tipo in fase di compilazione, che consentono di dichiarare
che la proprietà visible dell’esempio precedente contenga solamente un valore booleano.
Anche la nuova parola chiave extends semplifica il processo di creazione delle sottoclassi.
Nell’esempio seguente, la procedura in due fasi necessaria in ActionScript 1.0 viene portata a
termine in una sola fase, grazie all’introduzione della parola chiave extends:
La funzione di costruzione viene ora dichiarata come parte della definizione della classe e le
proprietà di classe id e radius devono anch’esse essere dichiarate esplicitamente.
In ActionScript 2.0 è stato inoltre introdotto il supporto della definizione di interfacce, che
consente di rendere ancora più specifici i programmi orientati agli oggetti mediante protocolli
formalmente definiti per la comunicazione tra oggetti.
T CA
Class.prototype Object.prototype
delegato delegato
prototipo costruttore
tipo C A P A
traits
T A
Ogni rettangolo del diagramma rappresenta un oggetto. Ogni oggetto del diagramma
presenta una lettera A in carattere pedice a indicare che appartiene alla classe A. L’oggetto di
classe (CA) contiene riferimenti a vari altri oggetti importanti. L’oggetto traits dell’istanza (TA)
contiene in memoria le proprietà dell’istanza definite nella definizione della classe. L’oggetto
traits della classe (TCA) rappresenta il tipo interno della classe e contiene in memoria le
proprietà statiche definite dalla classe (la lettera C in carattere pedice sta per “classe”).
L’oggetto prototype (PA) si riferisce sempre all’oggetto di classe al quale era originariamente
associato mediante la proprietà constructor.
Oggetto traits
L’oggetto traits, una novità di ActionScript 3.0, è stato implementato ai fini delle prestazioni.
Nelle versioni precedenti di ActionScript, il processo di ricerca dei nomi poteva risultare lento
e laborioso, in quanto Flash Player doveva risalire l’intera catena di prototipi. In ActionScript
3.0, le operazioni di ricerca dei nomi sono molto più efficienti e veloci, poiché le proprietà
ereditate vengono copiate dalle superclassi negli oggetti traits delle sottoclassi.
L’oggetto traits non è direttamente accessibile dal codice di programmazione, tuttavia, la sua
presenza è riscontrabile in termini di miglioramenti delle prestazioni e dell’uso della memoria.
L’oggetto traits fornisce ad AVM2 informazioni dettagliate sul layout e il contenuto delle classi.
Grazie a tali informazioni, AVM2 è in grado di ridurre sensibilmente i tempi di esecuzione, in
quanto può generare spesso istruzioni dirette alla macchina per l’accesso immediato a proprietà
o il richiamo di metodi, senza che siano necessarie lente e laboriose ricerche di nomi.
Oggetto prototype
Ogni classe di ActionScript presenta una proprietà chiamata prototype che funge da
riferimento all’oggetto prototype della classe. L’oggetto prototype è un retaggio delle origini di
ActionScript come linguaggio basato sui prototipi. Per ulteriori informazioni, vedere
“ActionScript 1.0” a pagina 185.
La proprietà prototype è una proprietà di sola lettura, vale a dire che non può essere
modificata per puntare a oggetti differenti. Ciò la differenzia dalla proprietà di classe
prototype delle versioni precedenti di ActionScript, dove era possibile riassegnare il
prototipo in modo che puntasse a una classe diversa. Nonostante la proprietà prototype sia
di sola lettura, l’oggetto prototype a cui fa riferimento non lo è. In altre parole, è possibile
aggiungere nuove proprietà all’oggetto prototype. Le proprietà aggiunte all’oggetto prototype
vengono condivise tra tutte le istanze della classe.
La catena di prototipi, che era il solo meccanismo di ereditarietà delle versioni precedenti di
ActionScript, ha soltanto un ruolo secondario in ActionScript 3.0. Il sistema di ereditarietà
primario, l’ereditarietà di proprietà fisse, viene gestito internamente dall’oggetto traits. Una
proprietà fissa è una variabile o metodo definito in una definizione di classe. L’ereditarietà
delle proprietà fisse è chiamata anche ereditarietà di classe, in quanto il meccanismo di
ereditarietà è associato a parole chiave quali class, extends e override.
La catena di prototipi offre un meccanismo di ereditarietà alternativo molto più dinamico
dell’ereditarietà di proprietà fisse. È possibile aggiungere proprietà all’oggetto prototype di
una classe non solo come parte della definizione della classe, ma anche in fase di runtime
mediante la proprietà prototype dell’oggetto di classe. Si tenga presente, tuttavia, che se si
imposta il compilatore in modalità rigorosa, potrebbe essere possibile accedere a proprietà
aggiunte a un oggetto prototype solo se la classe è stata dichiarata con la parola chiave
dynamic.
Infine, è possibile definire una proprietà fissa denominata valueOf() come parte della classe
Foo. Questa tecnica si differenzia dalle altre in quanto mescola il sistema di ereditarietà di
proprietà fisse con il sistema di ereditarietà di prototipi. Tutte le sottoclassi di Foo che
desiderano ridefinire valueOf() devono utilizzare la parola chiave override. Nel codice
seguente è illustrato valueOf() definito come proprietà fissa di Foo:
class Foo
{
function valueOf():String
{
return "Instance of Foo";
}
}
Oppure, è possibile utilizzare la direttiva use namespace per aprire lo spazio dei nomi AS3 di
tutte le definizioni racchiuse in un blocco di codice. Ad esempio, il codice seguente impiega la
direttiva use namespace per aprire lo spazio dei nomi di AS3 dei metodi pop() e push():
use namespace AS3;
ActionScript 3.0 presenta inoltre opzioni del compilatore per ciascuna serie di proprietà, per
consentire l’applicazione dello spazio dei nomi di AS3 all’intero programma. L’opzione del
compilatore -as3 rappresenta lo spazio dei nomi di AS3, mentre l’opzione del compilatore
-es rappresenta l’opzione di ereditarietà dei prototipi (es sta per ECMAScript). Per aprire lo
spazio dei nomi di AS3 per l’intero programma, impostare l’opzione del compilatore -as3 su
true e l’opzione del compilatore -es su false. Per utilizzare le versioni dei prototipi,
impostare le opzioni del compilatore sui valori opposti. Le impostazioni predefinite del
compilatore per Adobe Flex Builder 2 e Adobe Flash CS3 Professional sono -as3 = true e
-es = false.
Se si ha l’intenzione di estendere una delle classi principali e di sostituire uno o più metodi, è
necessario comprendere come lo spazio dei nomi di AS3 può influenzare la modalità di
dichiarazione di un metodo sostituito. Se si utilizza lo spazio dei nomi di AS3, anche in ogni
sostituzione di metodo di una classe principale è necessario utilizzare lo spazio dei nomi di
AS3 insieme all’attributo override. Se non si usa lo spazio dei nomi di AS3 e si desidera
ridefinire un metodo di classe principale all’interno di una sottoclasse, non è necessario
utilizzare lo spazio dei nomi di AS3 né la parola chiave override.
File Descrizione
GeometricShapes.mxml Il file principale dell’applicazione in Flash (FLA)
o o Flex (MXML)
GeometricShapes.fla
Circle RegularPolygon
+diameter:Number +numSides : int
+Circle () : Circle +sideLength : Number
+getArea () : Number +RegularPolygon (): RegularPolygon
+describe () : String +getSumOfAngles (): Number
+getCircumference () : Number +getPerimeter (): Number
+getArea (): Number
+describe (): String
EquilateralTriangle Square
L’interfaccia definisce due metodi: il metodo getArea(), che calcola e restituisce l’area della
figura geometrica, e il metodo describe(), che assembla una descrizione in formato testo
delle proprietà della figura.
Si desidera inoltre conoscere il perimetro di ciascuna figura. Tuttavia, il perimetro del cerchio
viene definito circonferenza e viene calcolato in modo univoco, di conseguenza, in questo
caso, il comportamento differisce da quello per calcolare il perimetro di un triangolo o un
quadrato. Vi sono comunque sufficienti somiglianze tra triangoli, quadrati e altri poligoni da
consentire la definizione di una nuova classe di interfaccia esclusiva per tali figure: IPolygon.
Anche l’interfaccia IPolygon è piuttosto semplice, come illustrato di seguito:
package com.example.programmingas3.geometricshapes
{
public interface IPolygon extends IGeometricShape
{
function getPerimeter():Number;
function getSumOfAngles():Number;
}
}
Questa interfaccia definisce due metodi comuni a tutti i poligoni: il metodo getPerimeter()
che misura la distanza combinata di tutti i lati e il metodo getSumOfAngles() che somma
tutti gli angoli interni.
L’interfaccia IPolygon estende l’interfaccia IGeometricShape, di conseguenza, tutte le classi
che implementano l’interfaccia IPolygon devono dichiarare tutti e quattro i metodi, i due
dell’interfaccia IGeometricShape e i due dell’interfaccia IPolygon.
In primo luogo, la classe RegularPolygon dichiara due proprietà comuni a tutti i poligoni
regolari: la lunghezza di ciascun lato (proprietà sideLength) e il numero di lati
(proprietà numSides).
La classe RegularPolygon implementa l’interfaccia IPolygon e dichiara tutti e quattro i metodi
dell’interfaccia IPolygon. Essa implementa inoltre due di essi (getPerimeter() e
getSumOfAngles()) utilizzando formule comuni.
Poiché la formula del metodo getArea() è diversa in base al tipo di figura geometrica, la
versione della classe base del metodo non può includere logica comune ereditabile dai metodi
delle sottoclassi. Al contrario, essa restituisce semplicemente un valore 0 predefinito, a
indicare che l’area non è stata calcolata. Per calcolare correttamente l’area di ogni figura
geometrica, le sottoclassi della classe RegularPolygon devono sostituire il metodo getArea().
Il codice seguente della classe EquilateralTriangle mostra come è possibile sostituire il metodo
getArea():
package com.example.programmingas3.geometricshapes
{
public class EquilateralTriangle extends RegularPolygon
{
public function EquilateralTriangle(len:Number = 100):void
{
super(len, 3);
}
case "Square":
return new Square(len);
Il metodo factory createShape() consente alle funzioni di costruzione delle sottoclassi delle
figure geometriche di definire i dettagli delle istanze da esse create, ma di restituire i nuovi
oggetti come istanze di IGeometricShape, in modo che possano essere gestiti dall’applicazione
in maniera più generica.
Il metodo describeShape() dell’esempio precedente mostra come un’applicazione può
utilizzare il metodo factory per ottenere un riferimento generico a un oggetto più specifico.
L’applicazione è in grado di ottenere la descrizione di un oggetto Circle appena creato
come segue:
GeometricShapeFactory.describeShape(“Circle”, 100);
Il metodo describeShape() richiama quindi il metodo factory createShape() con gli stessi
parametri, memorizzando il nuovo oggetto Circle in una variabile statica denominata
currentShape, originariamente inserita come un oggetto di IGeometricShape. Quindi, viene
chiamato il metodo describe() sull’oggetto currentShape e la chiamata viene
automaticamente risolta per eseguire il metodo Circle.describe(), che restituisce una
descrizione dettagliata del cerchio.
Sommario
Elementi fondamentali di date e orari. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
Gestione di date e orari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206
Controllo degli intervalli di tempo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 210
Esempio: Orologio analogico semplice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
205
Operazioni comuni con date e orari
In questo capitolo vengono descritte le seguenti operazioni comuni eseguibili con le
informazioni su date e orari:
■ Operazioni con oggetti Date
■ Determinazione del giorno e dell’orario corrente
■ Accesso a singole unità di tempo e di data (giorni, anni, ore, minuti, ecc.)
■ Esecuzione di operazioni aritmetiche con date e orari
■ Conversione di fusi orari
■ Esecuzione di azioni ripetute
■ Esecuzione di azioni dopo un intervallo di tempo prestabilito
Terzo, è possibile trasmettere più parametri numerici alla funzione di costruzione Date().
Tali parametri vengono trattati rispettivamente come anno, mese, giorno, ora, minuto,
secondo e millesimo di secondo e viene restituito un oggetto Date corrispondente. I seguenti
parametri di input sono espressi in ora locale anziché in UTC. Le istruzioni seguenti
consentono di creare un oggetto Date impostato sulla mezzanotte del 1 gennaio 2000,
in UTC:
var millenium:Date = new Date(2000, 0, 1, 0, 0, 0, 0);
Grazie alle unità di tempo standard, sarà più semplice eseguire operazioni aritmetiche con le
date. Il codice seguente consente di impostare un valore di data su un’ora a partire dall’ora
corrente mediante i metodi getTime() e setTime():
var oneHourFromNow:Date = new Date();
oneHourFromNow.setTime(oneHourFromNow.getTime() + millisecondsPerHour);
Un altro modo per impostare un valore di data è creare un nuovo oggetto Date utilizzando un
unico parametro di millesimi di secondo. Ad esempio, il codice seguente consente di
aggiungere 30 giorni a una data per calcolarne un’altra:
// Imposta la data fattura sulla data corrente
var invoiceDate:Date = new Date();
Cicli e timer
In alcuni linguaggi di programmazione, è necessario applicare schemi di gestione del tempo
propri mediante istruzioni di cicliche quali for o do..while.
Le istruzioni cicliche vengono generalmente eseguite alla massima velocità consentita dal
sistema, di conseguenza, l’applicazione risulterà più veloce su alcune macchine rispetto ad
altre. Se l’applicazione che si sta eseguendo necessita di un intervallo di tempo regolare, è
necessario collegarlo a un calendario o a un orologio. Molte applicazioni, quali giochi,
animazioni e controller in tempo reale, richiedono meccanismi di scansione temporale
regolari e omogenei tra un computer e l’altro.
La classe Timer di ActionScript 3.0 offre una soluzione efficace al problema. Grazie al modello
eventi di ActionScript 3.0, la classe Timer è in grado di inviare eventi timer ogni volta che
viene raggiunto un intervallo di tempo specificato.
L’oggetto Timer invia un oggetto TimerEvent ogni volta che viene raggiunto l’intervallo di
tempo specificato. Un tipo di evento dell’oggetto TimerEvent è timer (definito dalla costante
TimerEvent.TIMER). Un oggetto TimerEvent contiene le stesse proprietà dell’oggetto
standard Event.
Se l’istanza Timer viene impostata per un determinato numero di intervalli, essa invierà anche
un evento timerComplete (definito dalla costante TimerEvent.TIMER_COMPLETE) quando
viene raggiunto l’intervallo finale.
Segue una breve applicazione di esempio che illustra il funzionamento della classe Timer:
package
{
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
Quando viene creata la classe ShortTimer, viene creata anche un’istanza Timer che esegue un
controllo una volta al secondo per cinque secondi. Quindi vengono aggiunti due listener al
timer: uno che intercetta ogni conteggio di controllo e l’altro che resta in attesa dell’evento
timerComplete.
Quindi, viene avviato il conteggio del timer e, da quel momento in poi, il metodo onTick()
viene eseguito a intervalli di un secondo.
Il metodo onTick() visualizza semplicemente il conteggio temporale corrente. Dopo cinque
secondi, viene eseguito il metodo onTimerComplete(), che avverte che il tempo è scaduto.
Quando si esegue questo esempio, sulla console o sulla finestra di traccia dovrebbero apparire
le seguenti righe alla velocità di una riga al secondo:
tick 1
tick 2
tick 3
tick 4
tick 5
Time's Up!
Funzione Descrizione
clearInterval(id:uint):void Annulla una chiamata setInterval()
specifica.
clearTimeout(id:uint):void Annulla una chiamata setTimeout() specifica.
Queste funzioni sono incluse in ActionScript 3.0 al fine di assicurare la compatibilità con le
versioni precedenti. Adobe sconsiglia di utilizzare nelle nuove applicazioni di ActionScript 3.0.
In generale, l’uso della classe Timer nelle applicazioni risulta più facile e più efficace.
File Descrizione
SimpleClockApp.mxml Il file principale dell’applicazione in Flash (FLA)
o o Flex (MXML)
SimpleClockApp.fla
/**
* Timer che scandisce il tempo dell’applicazione.
*/
private var ticker:Timer;
Per prima cosa viene creata un’istanza di Timer che invia un evento una volta al secondo (ogni
1000 millesimi di secondo). Poiché alla funzione di costruzione Timer() non viene trasmesso
nessun secondo parametro repeatCount, il Timer continuerà a ripetere l’operazione
all’infinito.
Il metodo SimpleClock.onTick() verrà eseguito una volta al secondo quando viene ricevuto
l’evento timer:
public function onTick(event:TimerEvent):void
{
// Aggiorna la visualizzazione dell’orologio
face.draw();
}
Questo metodo consente di salvare l’ora corrente in una variabile, di modo che l’ora non
venga modificata nella fase di disegno delle lancette. Quindi viene chiamato il metodo
showTime() per visualizzare le lancette, come riportato di seguito:
/**
* Visualizza data e ora nell’orologio analogico.
*/
public function showTime(time:Date):void
{
// Determina i valori di ora
var seconds:uint = time.getSeconds();
var minutes:uint = time.getMinutes();
var hours:uint = time.getHours();
In primo luogo, questo metodo consente di estrarre i valori di ore, minuti e secondi dell’ora
corrente. Quindi impiega questi valori per calcolare l’angolo di ogni lancetta. Poiché la
lancetta dei secondi effettua una rotazione completa in 60 secondi, essa ruota di 6 gradi al
secondo (360/60). La lancetta dei minuti effettua la stessa rotazione ogni minuto.
Anche la lancetta delle ore viene aggiornata ogni minuto, in modo che avanzi di un grado con
trascorrere dei minuti. Essa ruota di 30 gradi ogni ora (360/12), ma anche di mezzo grado
ogni minuto (30 gradi diviso 60 minuti).
Sommario
Elementi fondamentali delle stringhe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
Creazione di stringhe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219
Proprietà length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Operazioni con i caratteri nelle stringhe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Confronto tra stringhe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .222
Come ottenere rappresentazioni di altri oggetti sotto forma di stringa. . . . . . . . . .223
Concatenazione di stringhe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .223
Ricerca di sottostringhe e modelli nelle stringhe . . . . . . . . . . . . . . . . . . . . . . . . . . . . .224
Conversione di stringhe da maiuscole a minuscole . . . . . . . . . . . . . . . . . . . . . . . . . 230
Esempio: ASCII Art . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230
217
Come illustrato da questo esempio, in ActionScript è possibile indicare un valore di stringa
racchiudendo il testo tra virgolette semplici o doppie. Seguono altri esempi di stringhe:
"Hello"
"555-7649"
"http://www.adobe.com/"
Ogni volta che si manipola una porzione di testo in ActionScript, si lavora con un valore di
stringa. La classe String di ActionScript è il tipo di dati da utilizzare per eseguire operazioni
con i valori di testo. Le istanze String vengono spesso impiegate per proprietà, metodi,
parametri e così via, in molte altre classi di ActionScript.
Creazione di stringhe
La classe String viene utilizzata per rappresentare dati di stringa (testuali) in ActionScript 3.0.
Le stringhe di ActionScript 3.0 supportano sia i caratteri ASCII che Unicode. Il modo più
semplice per creare una stringa è di usare un carattere letterale. Per dichiarare un valore
letterale di stringa, utilizzare le virgolette doppie diritte (") o le virgolette semplici ('). Ad
esempio, le due stringhe seguenti sono equivalenti:
var str1:String = "hello";
var str2:String = 'hello';
Per dichiarare una stringa è inoltre possibile utilizzare l’operatore new, come di seguito:
var str1:String = new String("hello");
var str2:String = new String(str1);
var str3:String = new String(); // str3 == ""
Per utilizzare le virgolette semplici (') all’interno di una stringa delimitata da virgolette
semplici ('), utilizzare il carattere barra rovesciata (\). Analogamente, per utilizzare le
virgolette doppie (") all’interno di una stringa delimitata da virgolette doppie ("), utilizzare il
carattere barra rovesciata (\). Le due stringhe seguenti sono equivalenti:
var str1:String = "That's \"A-OK\"";
var str2:String = 'That\'s "A-OK"';
Tenere presente che ActionScript fa distinzione tra virgolette singole dritte (') e virgolette
singole curve (‘ o ’). Lo stesso vale per le virgolette doppie. Per contraddistinguere i valori
letterali di stringa utilizzare sempre le virgolette dritte. Se si incolla testo da una fonte esterna
in ActionScript, verificare di utilizzare i caratteri corretti.
Come illustrato nella tabella seguente, per definire altri caratteri nei valori letterali di stringa, è
possibile utilizzare il carattere barra rovesciata (\).
Sequenza di Carattere
escape
\b Backspace
\f Avanzamento pagina
\n Nuova riga
\r Ritorno a capo
\t Tabulazione
\unnnn Carattere Unicode con il codice carattere specificato dal numero
esadecimale nnnn; ad esempio, \u263a è il carattere smiley.
\xnn Carattere ASCII con il codice di carattere specificato mediante il
numero esadecimale nn.
\’ Virgolette semplici
\" Virgolette doppie
\\ Barra rovesciata singola
Se una stringa è nulla o vuota la sua lunghezza corrisponde a 0, come nell’esempio seguente:
var str1:String = new String();
trace(str1.length); // output: 0
str2:String = '';
trace(str2.length); // output: 0
Utilizzare gli operatori == e != per confrontare le stringhe tra loro e per confrontare le stringhe
con altri tipi di oggetti, come nell’esempio seguente:
var str1:String = "1";
var str1b:String = "1";
var str2:String = "2";
trace(str1 == str1b); // true
trace(str1 == str2); // false
var total:uint = 1;
trace(str1 == total); // true
Concatenazione di stringhe
Concatenare più stringhe significa prendere due stringhe e unirle in modo sequenziale per
formare un’unica stringa. Ad esempio, è possibile utilizzare l’operatore + per concatenare due
stringhe:
var str1:String = "green";
var str2:String = "ish";
var str3:String = str1 + str2; // str3 == "greenish"
È inoltre possibile ottenere lo stesso risultato con l’operatore +=, come nell’esempio seguente:
var str:String = "green";
str += "ish"; // str == "greenish"
Inoltre, la classe String include un metodo concat(), che può essere utilizzato come segue:
var str1:String = "Bonjour";
var str2:String = "from";
var str3:String = "Paris";
var str4:String = str1.concat(" ", str2, " ", str3);
// str4 == "Bonjour from Paris"
Se si usa l’operatore + (o l’operatore +=) con un oggetto String e un oggetto diverso da una
stringa, ActionScript converte automaticamente l’oggetto non-stringa in un oggetto String per
poter valutare l’espressione, come nell’esempio seguente:
var str:String = "Area = ";
var area:Number = Math.PI * Math.pow(3, 2);
str = str + area; // str == "Area = 28.274333882308138"
ActionScript include metodi per cercare i modelli nelle stringhe e per sostituire le
corrispondenze trovate con sottostringhe. Tali metodi vengono descritti più dettagliatamente
nelle sezioni che seguono.
Le espressioni regolari sono in grado di definire modelli intricati. Per ulteriori informazioni,
vedere Capitolo 9, “Uso delle espressioni regolari” a pagina 305.
Come parametri del metodo slice(), è possibile combinare numeri interi non negativi e
negativi.
Il risultato del metodo trace() è 0, in quanto il primo carattere della stringa si trova nella
posizione di indice. L’indicatore i viene impostato nell’espressione regolare, in modo che nella
ricerca non si faccia distinzione tra maiuscole e minuscole.
Il metodo search() consente di trovare solo una corrispondenza e restituisce la sua posizione
di indice iniziale, anche se l’indicatore g (global) viene impostato nell’espressione regolare.
Nell’esempio seguente è illustrata un’espressione regolare più complessa, che deve
corrispondere a una stringa racchiusa tra virgolette doppie:
var pattern:RegExp = /"[^"]*"/;
var str:String = "The \"more\" the merrier.";
trace(str.search(pattern)); // output: 4
Il metodo match() funziona in modo simile. Esso consente di cercare una sottostringa
corrispondente. Tuttavia, se si usa l’indicatore global in un modello di espressione regolare,
come nell’esempio seguente, il metodo match() restituisce un array di sottostringhe
corrispondenti:
var str:String = "[email protected], [email protected]";
var pattern:RegExp = /\w*@\w*\.[org|com]+/g;
var results:Array = str.match(pattern);
Per ulteriori informazioni sulle espressioni regolari, vedere Capitolo 9, “Uso delle espressioni
regolari” a pagina 305.
Si noti come, nell’esempio, nelle stringe corrispondenti non si fa distinzione tra lettere
maiuscole e minuscole, in quanto è stato impostato l’indicatore i (ignoreCase)
nell’espressione regolare e le corrispondenze multiple vengono sostituite in quanto è stato
specificato l’indicatore g (global). Per ulteriori informazioni, vedere Capitolo 9, “Uso delle
espressioni regolari” a pagina 305.
Nella stringa di sostituzione è possibile includere i seguenti codici di sostituzione $. Il testo
di sostituzione visualizzato nella tabella seguente viene inserito al posto del codice di
sostituzione $ :
È possibile usare una funzione come secondo parametro del metodo replace(). Il testo
corrispondente viene sostituito dal valore restituito dalla funzione.
var str:String = "Now only $9.95!";
var price:RegExp = /\$([\d,]+.\d+)+/i;
trace(str.replace(price, usdToEuro));
function usdToEuro(matchedSubstring:String,
capturedMatch1:String,
index:int,
str:String):String
{
var usd:String = capturedMatch1;
usd = usd.replace(",", "");
var exchangeRate:Number = 0.853690;
var euro:Number = usd * exchangeRate;
const euroSymbol:String = String.fromCharCode(8364);
return euro.toFixed(2) + " " + euroSymbol;
}
Se si usa una funzione come secondo parametro del metodo replace(), alla funzione
vengono inviati i seguenti argomenti:
■ La porzione corrispondente della stringa.
■ Tutte le corrispondenze dei gruppi parentetici catturati. Il numero di argomenti passati in
questo modo varia a seconda del numero di corrispondenze parentetiche. È possibile
determinare il numero di corrispondenze parentetiche verificando il valore
arguments.length - 3 all’interno del codice della funzione.
■ La posizione di indice nella stringa in cui inizia la corrispondenza.
■ La stringa completa.
Dopo l’esecuzione di questi metodi, la stringa di origine rimane invariata. Per trasformare la
stringa di origine, utilizzare il codice seguente:
str = str.toUpperCase();
Questi metodi funzionano con caratteri estesi, non semplicemente a–z e A–Z:
var str:String = "José Barça";
trace(str.toUpperCase(), str.toLowerCase()); // JOSÉ BARÇA josé barça
File Descrizione
AsciiArtApp.mxml Il file dell’applicazione principale in Flash (FLA)
o o Flex (MXML)
AsciiArtApp.fla
com/example/programmingas3/asciiArt/ Classe che fornisce le funzionalità principali
AsciiArtBuilder.as dell’applicazione, inclusa l’estrazione dei
metadati dell’immagine da un file di testo, il
caricamento delle immagini e la gestione del
processo di conversione immagine-testo.
com/example/programmingas3/asciiArt/ Classe che fornisce il metodo
BitmapToAsciiConverter.as parseBitmapData() per la conversione dei dati
immagini in versione stringa.
Il file impiega un formato specifico delimitato da tabulazione. La prima riga è una riga di
intestazione. Le restanti righe contengono i seguenti dati per ciascuna bitmap da caricare:
■ Il nome file della bitmap.
■ Il nome di visualizzazione della bitmap.
■ I valori di soglia del bianco e soglia del nero per le bitmap. Si tratta di valori
esadecimali al di sopra o al di sotto dei quali un pixel viene considerato completamente
bianco o completamente nero.
Tutto il contenuto del file di testo è racchiuso in una sola istanza di String, la proprietà
_imageInfoLoader.data. Utilizzando il metodo split() con il carattere nuova riga ("\n")
come parametro, l’istanza String viene divisa in un array (lines) i cui elementi sono singole
righe del file di testo. Quindi, il codice impiega un ciclo per lavorare con ogni singola riga
(tranne la prima, che contiene solo l’intestazione). All’interno del ciclo, il metodo split()
viene utilizzato di nuovo per dividere il contenuto della singola riga in una serie di valori
(l’oggetto Array chiamato imageProperties). Il parametro utilizzato con il metodo split()
in questo caso è il carattere tabulazione ("\t"), in quanto i valori di ogni riga sono delimitati
dalla tabulazione.
In questo codice, il titolo dell’immagine viene trasmesso dal file di testo attraverso il metodo
normalizeTitle() prima di essere memorizzato nell’oggetto ImageInfo:
private function normalizeTitle(title:String):String
{
var words:Array = title.split(" ");
var len:uint = words.length;
for (var i:uint; i < len; i++)
{
words[i] = capitalizeFirstLetter(words[i]);
}
Questo metodo impiega il metodo split() per dividere il titolo in singole parole (separate
dal carattere spazio), passa ogni singola parola attraverso il metodo
capitalizeFirstLetter(), quindi usa il metodo join() della classe Array per combinare le
parole di nuovo in un’unica stringa.
Nei titoli, il primo carattere delle seguenti parole non viene scritto in maiuscolo: “e”, “il”, “in”,
“un”, “o”, “a”, “di”, “per”, ecc. (in genere, si tratta di articoli e preposizioni). Per eseguire
questa logica, il codice impiega un’istruzione switch per verificare se la parola è tra quelle che
non devono essere scritte in maiuscolo. In tal caso, il codice salta semplicemente l’istruzione
switch. Se invece la parola deve essere scritta in maiuscolo, l’operazione di trasformazione
viene eseguita in varie fasi:
1. La prima lettera della parola viene estratta mediante la funzione substr(0, 1), che
consente di estrarre una sottostringa che inizia con il carattere in posizione di indice 0
(la prima lettera della stringa, come indicato dal primo parametro 0). La sottostringa è
lunga un solo carattere (indicato dal secondo parametro 1).
2. Tale carattere viene scritto in maiuscolo utilizzando il metodo toUpperCase().
Poiché la variabile index definisce quale carattere ASCII nella tavolozza corrisponde al pixel
corrente dell’immagine bitmap, tale carattere viene recuperato dalla stringa palette mediante
il metodo charAt(). Quindi, esso viene aggiunto all’istanza di String result mediante
l’operatore di assegnazione della concatenazione (+=). Inoltre, alla fine di ogni riga di pixel, un
carattere nuova riga viene concatenato alla fine della stringa result, per obbligare la riga a
tornare a capo e creare una nuova riga di “pixel” di caratteri.
Sommario
Elementi fondamentali degli array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .239
Array con indice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .242
Array associativi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
Array multidimensionali . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .256
Clonazione di array. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .258
Argomenti avanzati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
Esempio: PlayList. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .265
239
Un array è un elemento di programmazione che funge da contenitore per una serie di voci,
quale un elenco di brani. Generalmente, tutti gli elemento di un array sono istanze di una
stessa classe, ma ciò non è un requisito di ActionScript. Le singole voci di un array sono
conosciute come gli elementi dell’array. Un array può essere considerato come una directory
contenente variabili. Le variabili possono essere inserite come elementi nell’array, esattamente
come si inserisce una cartella in una directory. Una volta inseriti vari file nella directory, è
possibile lavorare con l’array come se fosse un’unica variabile (ad esempio, è possibile
trasportare l’intera directory in un’alta posizione), è possibile lavorare con le variabili come se
fossero un unico gruppo (ad esempio, è possibile sfogliare le cartelle una a una per cercare una
particolare informazione), oppure è possibile accedere a esse individualmente (come aprire la
directory e selezionare una cartella).
Ad esempio, si immagini di creare un’applicazione di riproduzione musicale in cui sia possibile
selezionare più brani e aggiungerli a un elenco di riproduzione. Nel codice ActionScript, è
possibile inserire un metodo chiamato addSongsToPlaylist() che accetta un singolo array
come parametro. Indipendentemente dal numero di brani da inserire nell’elenco (pochi, molti
o uno soltanto), è necessario chiamare il metodo addSongsToPlaylist() una sola volta, per
passarlo nell’array contenente gli oggetti Song. All’interno del metodo
addSongsToPlaylist(), è possibile usare una funzione ciclica per passare in rassegna i vari
elementi dell’array (i brani) uno a uno e aggiungerli all’elenco di riproduzione.
Il tipo di array più comune in ActionScript è l’array indicizzato, un array dove ogni elemento
viene memorizzato in uno slot numerato (detto indice) e le voci sono accessibili mediante
numeri, come negli indirizzi. La classe Array viene impiegata per rappresentare array
indicizzati. Gli array indicizzati sono in grado di soddisfare la maggior parte delle esigenze di
programmazione. Un impiego speciale dell’array indicizzato è l’array multidimensionale, che
consiste in un array indicizzato i cui elementi sono altri array indicizzati (contenenti a loro
volta altri elementi). Un altro tipo di array è l’array associativo, che impiega una chiave in
formato stringa anziché un indice numerico per identificare i vari elementi. Infine, per gli
utenti avanzati, ActionScript 3.0 include anche la classe Dictionary, che rappresenta un vero e
proprio dizionario, un array che consente di utilizzare qualsiasi tipo di oggetto come chiave di
identificazione degli elementi.
La classe Array può inoltre contenere proprietà e metodi che consentono di modificare gli
array indicizzati. Tali proprietà e metodi vengono applicati quasi esclusivamente ad array
indicizzati piuttosto che ad array associativi.
Gli array con indice impiegano valori interi senza segni a 32 bit come numeri di indice.
La dimensione massima di un array con indice è 2321 o 4.294.967.295. Qualsiasi tentativo di
creare un array di dimensioni superiori genera un errore di runtime.
Creazione di array
La funzione di costruzione della classe Array può essere utilizzata in tre diversi modi. Primo: se
si chiama la funzione di costruzione senza argomenti, viene restituito un array vuoto.
Utilizzare la proprietà length della classe Array per verificare che l’array non contenga
elementi. Ad esempio, il codice seguente consente di chiamare la funzione di costruzione della
classe Array senza argomenti:
var names:Array = new Array();
trace(names.length); // output: 0
Secondo: se si usa un numero come unico parametro della funzione di costruzione della classe
Array, viene creato un array di lunghezza corrispondente, con il valore di ciascun elemento
impostato su undefined. L’argomento deve essere un numero intero senza segno compreso tra
0 e 4.294.967.295. Ad esempio, il codice seguente consente di chiamare la funzione di
costruzione Array con un solo argomento numerico:
var names:Array = new Array(3);
trace(names.length); // output: 3
trace(names[0]); // output: undefined
trace(names[1]); // output: undefined
trace(names[2]); // output: undefined
I metodi push() e unshift() restituiscono entrambi un numero intero senza segno che
rappresenta la lunghezza dell’array modificato. Il metodo splice() restituisce un array vuoto
se utilizzato per inserire elementi, cosa che potrebbe sembrare strana, ma che acquista maggior
senso alla luce della versatilità del metodo splice(). Il metodo splice() non consente solo
di inserire elementi in un array, ma anche di rimuovere elementi. Se utilizzato per rimuovere
elementi, il metodo splice() restituisce un array contenente gli elementi rimossi.
Ordinamento di un array
Sono disponibili tre diversi metodi di ordinamento: reverse(), sort() e sortOn(), che
consentono di modificare l’ordine di un array, mediante inversione dell’ordine o ordinamento
in base a un elemento specifico. Tutti i metodi consentono di modificare l’array esistente.
Il metodo reverse() modifica l’ordine dell’array in modo che l’ultimo elemento diventi il
primo, il penultimo elemento diventi il secondo e così via. Il metodo sort() consente di
ordinare un array in vari modi predefiniti e di creare algoritmi di ordinamento predefiniti.
Il metodo sortOn() consente di ordinare un array indicizzato di oggetti che presentano una o
più proprietà comuni da utilizzare come chiavi di ordinamento.
Il metodo reverse() non presenta parametri e non restituisce valori, ma permette di
alternare l’ordine dell’array dallo stato corrente a quello inverso. Nell’esempio seguente viene
invertito l’ordine degli oceani elencati nell’array oceans:
var oceans:Array = ["Arctic", "Atlantic", "Indian", "Pacific"];
oceans.reverse();
trace(oceans); // output: Pacific,Indian,Atlantic,Arctic
poets.sort(Array.CASEINSENSITIVE);
trace(poets); // output: Angelou,Blake,cummings,Dante
poets.sort(Array.DESCENDING);
trace(poets); // output: cummings,Dante,Blake,Angelou
È possibile utilizzare il metodo sortOn() per ordinare l’array in base alla proprietà born.
Il metodo sortOn() definisce due parametri, fieldName e options. L’argomento fieldName
deve essere specificato come stringa. Nell’esempio seguente, sortOn() viene chiamato con
due argomenti, "born" e Array.NUMERIC. L’argomento Array.NUMERIC viene utilizzato per
fare in modo che l’ordinamento sia numerico anziché alfabetico. Si tratta di un sistema
efficace quando tutti i valori presentano lo stesso numero di cifre, in quanto assicura che
l’ordinamento continuerà a essere eseguito correttamente anche se nell’array viene inserito un
valore con un numero di cifre inferiore o superiore.
poets.sortOn("born", Array.NUMERIC);
for (var i:int = 0; i < poets.length; ++i)
{
trace(poets[i].name, poets[i].born);
}
/* output:
Wang 701
Dante 1265
Blake 1757
cummings 1894
Angelou 1928
*/
Query di un array
I restanti metodi della classe Array (concat(), join(), slice(), toString()) consentono di
eseguire query nell’array per ottenere informazioni, senza modificare l’array. I metodi
concat() e slice() restituiscono nuovi array, mentre i metodi join() e toString()
restituiscono stringhe. Il metodo concat() impiega un nuovo array o un elenco di elementi
come argomenti e li combina con l’array esistente per creare un nuovo array. Il metodo
slice() impiega due parametri, denominati startIndex e endIndex, per restituire un
nuovo array contenente una copia degli elementi a “sezionati” dall’array esistente. Il
sezionamento inizia dall’elemento in posizione startIndex e termina con l’elemento che
precede endIndex. Questo sistema prevede la ripetizione: l’elemento in posizione endIndex
non è incluso nel valore restituito.
Nell’esempio seguente, vengono utilizzati i metodi concat() e slice() per creare nuovi
array utilizzando elementi di altri array:
var array1:Array = ["alpha", "beta"];
var array2:Array = array1.concat("gamma", "delta");
trace(array2); // output: alpha,beta,gamma,delta
Quando si usa il metodo join(), tenere presente che gli array nidificati vengono sempre
restituiti con valori separati da virgola, a prescindere dal tipo di separatore specificato per gli
elementi dell’array principale, come illustrato nell’esempio seguente:
var nested:Array = ["b","c","d"];
var letters:Array = ["a",nested,"e"];
var joined:String = letters.join("+");
trace(joined); // output: a+b,c,d+e
Array associativi
Gli array associativi, talvolta chiamati anche hash o mappe, impiegano chiavi anziché indici
numerici per organizzare i valori memorizzati. Ogni chiave di un array associativo è una
stringa univoca che consente di accedere a un valore memorizzato. Gli array associativi sono
istanze della classe Object, di conseguenza, ogni chiave corrisponde a un nome di proprietà.
Gli array associativi sono insiemi di coppie chiave/valore non ordinati. Le chiavi di un array
associativo non sono mai in un ordine specifico.
ActionScript 3.0 introduce un tipo di array associativo avanzato denominato dizionario.
I dizionari, che sono istanze della classe Dictionary nel pacchetto flash.utils, impiegano chiavi
di qualsiasi tipo di dati, ma che sono in genere istanze della classe Object. In altre parole, le
chiavi dei dizionari non soli limitate a valori di tipo String.
In questa sezione viene illustrato come creare array associativi che impiegano stringhe come
chiavi e come usare la classe Dictionary.
Dopo che l’array viene creato utilizzando il valore letterale oggetto o la funzione di
costruzione della classe Object, è possibile aggiungere nuovi valori all’array mediante
l’operatore parentesi ([]) o l’operatore punto (.). Nell’esempio seguente vengono aggiunti
due nuovi valori a monitorArray:
monitorInfo["aspect ratio"] = "16:10"; // Forma errata, non usare spazi
monitorInfo.colors = "16.7 million";
trace(monitorInfo["aspect ratio"], monitorInfo.colors);
// output: 16:10 16,7 milioni
Si noti come la chiave denominata aspect ratio contenga un carattere spazio. Questa
operazione è possibile con l’operatore parentesi quadra, ma genera un errore se si tenta di
effettuarla con l’operatore punto. L’uso di spazi nei nomi delle chiavi è sconsigliato.
In alternativa, per creare un array associativo è possibile utilizzare la funzione di costruzione
Array e quindi l’operatore parentesi quadra ([]) o l’operatore punto (.) per aggiungere coppie
chiave/valore all’array. Se si dichiara un array associativo di tipo Array, non è possibile
utilizzare un valore letterale oggetto per inizializzare l’array. L’esempio seguente crea un array
associativo denominato monitorInfo utilizzando la funzione di costruzione Array e aggiunge
una chiave denominata type e una denominata resolution con i relativi valori.
var monitorInfo:Array = new Array();
monitorInfo["type"] = "Flat Panel";
monitorInfo["resolution"] = "1600 x 1200";
trace(monitorInfo["type"], monitorInfo["resolution"]);
// output: Flat Panel 1600 x 1200
if (groupMap[spr1] == groupA)
{
trace("spr1 is in groupA");
}
Utilizzare il ciclo for each..in per accedere direttamente ai valori di un oggetto Dictionary.
Anche nel codice seguente viene utilizzato il dizionario groupMap per illustrare come eseguire
un’iterazione in un oggetto Dictionary con il ciclo for each..in:
for each (var item:Object in groupMap)
{
trace(item);
}
/* output:
[oggetto Object]
[oggetto Object]
[oggetto Object]
*/
Fintanto che esiste un riferimento all’oggetto, il sistema di garbage collection non ripristinerà
la memoria occupata dall’oggetto. Se il valore di myObject viene modificato in modo da
puntare a un oggetto differente o viene impostato sul valore null, la memoria occupata
dall’oggetto originale diventa disponibile per la garbage collection, ma solo se non vi sono altri
riferimenti che puntano all’oggetto originale.
Se si usa myObject come chiave in un oggetto Dictionary, si crea un altro riferimento
all’oggetto originale. Ad esempio, il codice seguente consente di creare due riferimenti a un
oggetto: la variabile myObject e la chiave nell’oggetto myMap:
import flash.utils.Dictionary;
Per fare in modo che l’oggetto a cui fa riferimento myObject diventi disponibile per la garbage
collection, è necessario rimuovere tutti i riferimenti. In questo caso, è necessario modificare il
valore di myObject ed eliminare la chiave myObject da myMap, come illustrato nel codice
seguente:
myObject = null;
delete myMap[myObject];
Se si desidera memorizzare un elenco separato di attività per ogni giorno della settimana, è
possibile creare un array multidimensionale con un elemento per ogni giorno della settimana.
Ogni elemento contiene un array indicizzato simile all’array tasks, che a sua volta contiene
l’elenco di attività. Negli array multidimensionali è possibile utilizzare qualsiasi combinazione
di array indicizzati o associativi. Gli esempi nelle sezioni che seguono impiegano due array
indicizzati o un array associativo di array indicizzati. È possibile provare altre combinazioni
come esercizio.
Per recuperare la prima attività dell’elenco di domenica, utilizzare l’indice 6 per domenica e
l’indice 0 per la prima attività in elenco.
trace(masterTaskList[6][0]); // output: mow lawn
La sintassi del punto rende il codice più facilmente leggibile, consentendo di evitare varie serie
di parentesi.
trace(masterTaskList.Wednesday[1]); // output: dentist
trace(masterTaskList.Sunday[0]); // output: mow lawn
Clonazione di array
La classe Array non presenta un metodo integrato per eseguire copie degli array. È possibile
creare una copia superficiale di un array chiamando il metodo concat() o slice() senza
argomenti. In una copia superficiale, se l’array originale presenta elementi che sono oggetti,
solo i riferimenti agli oggetti vengono copiati e non gli oggetti stessi. La copia punta agli stessi
oggetti dell’originale. Eventuali modifiche apportate agli oggetti vengono riprodotte in
entrambi gli array.
In una copia profonda, tutti gli oggetti rilevati nell’array originale sono copiati in modo che il
nuovo array non punti agli stessi oggetti dell’array originale. Per eseguire copie profonde è
necessaria più di una singola riga di codice, che in genere richiede la creazione di una
funzione. Tale funzione può essere creata come una funzione di utilità generale o come un
metodo di una sottoclasse di Array.
function clone(source:Object):*
{
var myBA:ByteArray = new ByteArray();
myBA.writeObject(source);
myBA.position = 0;
return(myBA.readObject());
}
Argomenti avanzati
Tutti e quattro i metodi sostituiti impiegano lo spazio dei nomi di AS3 anziché l’attributo
public perché in questo esempio si presuppone che l’opzione del compilatore -as3 sia
impostata su true e l’opzione del compilatore -es sia impostata su false. Queste sono le
impostazioni predefinite per Adobe Flex Builder 2 e per Adobe Flash CS3 Professional.
Per ulteriori informazioni, vedere “Spazio dei nomi di AS3” a pagina 192.
S UG G E R I ME N T O
File Descrizione
PlayList.mxml Il file principale dell’applicazione in Flash (FLA)
o o Flex (MXML)
PlayList.fla
com/example/programmingas3/playlist/ Oggetto valore rappresentante informazioni su
Song.as un singolo brano. Le voci gestite dalla classe
PlayList sono istanze di Song.
Proprietà di ordinamento
Un oggetto Song è in grado di tenere traccia di varie proprietà, incluso titolo del brano,
artista, anno di pubblicazione, nome del file e una serie di generi selezionati dall’utente
associati a ciascun brano. Tra queste proprietà, solo le prime tre sono utili per l’ordinamento.
Per ragioni di praticità, l’esempio include la classe SortProperty, che funge da elenco di valori
che rappresentano le proprietà disponibili per eseguire l’ordinamento.
public static const TITLE:SortProperty = new SortProperty("title");
public static const ARTIST:SortProperty = new SortProperty("artist");
public static const YEAR:SortProperty = new SortProperty("year");
La classe SortProperty contiene tre costanti, TITLE, ARTIST e YEAR, ognuna delle quali
contiene una stringa con il nome effettivo della proprietà della classe Song associata
utilizzabile per l’ordinamento. Nella parte restante del codice, per indicare una proprietà di
ordinamento viene utilizzato un membro dell’enumerazione. Ad esempio, nella funzione di
costruzione PlayList, l’elenco viene ordinato chiamando il metodo sortList(), come
indicato di seguito:
// Imposta l’ordinamento iniziale.
this.sortList(SortProperty.TITLE);
Poiché la proprietà in base alla quale eseguire l’ordinamento viene specificata come
SortProperty.TITLE, i brani vengono ordinati in base al titolo.
Quando si crea una nuova istanza di Song, il parametro genres utilizzato per specificare il
genere (o i generi) a cui il brano appartiene viene definito come un’istanza di Array. Ciò
consente di raggruppare facilmente più generi in una singola variabile da inviare alla funzione
di costruzione. Tuttavia, internamente, la classe Song conserva i generi nella variabile privata
_genres come un’istanza di String separata da punto e virgola. Il parametro Array viene
convertito in una stringa separata da punto e virgola mediante chiamata al metodo join()
con il valore letterale di stringa ";" come delimitatore specificato.
Grazie allo stesso token, gli accessor genres consentono l’impostazione o il recupero dei
generi come un array:
public function get genres():Array
{
// I generi sono memorizzati come stringhe separate da punto e virgola,
// di conseguenza, è necessario trasformarle in un Array per
ritrasmetterle indietro.
return this._genres.split(";");
}
public function set genres(value:Array):void
{
// I generi vengono trasmessi come un array,
// ma memorizzati come stringhe separate da punto e virgola.
this._genres = value.join(";");
}
Sommario
Elementi fondamentali della gestione degli errori . . . . . . . . . . . . . . . . . . . . . . . . . . . . 272
Tipi di errore. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
Gestione degli errori in ActionScript 3.0. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
Utilizzo della versione debugger di Flash Player . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
Gestione degli errori sincroni delle applicazioni. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 281
Creazione di classi di errore personalizzate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287
Risposte a eventi errore e a errori basati sullo stato . . . . . . . . . . . . . . . . . . . . . . . . . .288
Confronto tra le classi di tipo Error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .292
Esempio: Applicazione CustomErrors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .298
271
Elementi fondamentali della gestione
degli errori
Per ulteriori informazioni su queste tecniche per la prova degli esempi di codice, vedere “Prova
degli esempi di codice contenuti nei capitoli” a pagina 68.
Tipi di errore
Durante lo sviluppo e l’esecuzione di applicazioni si incontrano diversi tipi di errore e vari
termini relativi agli errori. Ecco un elenco dei principali tipi di errore e dei termini a essi
relativi:
■ Gli errori in fase di compilazione vengono generati dal compilatore ActionScript durante la
compilazione del codice e si verificano se sono presenti dei problemi di sintassi che
impediscono la compilazione del codice.
■ Gli errori in fase di runtime si verificano durante l’esecuzione dell’applicazione già
compilata e sono errori generati durante la riproduzione di un file SWF in Adobe Flash
Player 9. Nella maggior parte dei casi è possibile gestirli man mano che si incontrano,
comunicandoli all’utente e intervenendo in modo che l’applicazione non si interrompa.
Se l’errore è irreversibile, ad esempio se non è possibile collegarsi a un sito web remoto o
caricare dei dati necessari, la gestione degli errori permette di interrompere l’applicazione
normalmente.
In questo caso, l’errore in fase di runtime viene generato in modo sincrono perché Flash
Player determina che il metodo browse() non è stato chiamato prima del tentativo di
caricamento del file.
Per informazioni dettagliate sulla gestione degli errori sincroni, vedere “Gestione degli
errori sincroni delle applicazioni” a pagina 281.
■ Gli errori asincroni sono errori in fase di runtime che si verificano in momenti diversi
dell’esecuzione e che generano eventi rilevati da listener di eventi. In un’operazione
asincrona, una funzione avvia un’operazione senza attenderne il completamento. Si può
creare un listener di eventi errore che attenda una reazione da parte dell’applicazione o
dell’utente e, se l’operazione non va a buon fine, si rileva l’errore mediante il listener e si
risponde all’errore. A questo punto, il listener di eventi chiama una funzione di gestione
eventi che risponda all’errore in modo utile, per esempio, visualizzando una finestra di
dialogo con una richiesta di risolvere il problema diretta all’utente.
Consideriamo nuovamente l’esempio di errore sincrono presentato prima. Se si esegue una
chiamata corretta al metodo browse() prima di avviare il caricamento del file, Flash Player
invia vari eventi. Ad esempio, all’avvio del caricamento, viene inviato l’evento open. Quando
l’operazione di caricamento del file viene completata correttamente, viene inviato l’evento
complete. Poiché la gestione degli eventi è un’attività asincrona, cioè che non avviene in
momenti prestabiliti e conosciuti, è necessario usare il metodo addEventListener() per
intercettare questi eventi specifici, come illustra il codice seguente:
var fileRef:FileReference = new FileReference();
fileRef.addEventListener(Event.SELECT, selectHandler);
function selectHandler(event:Event):void
{
trace("...select...");
var request:URLRequest = new URLRequest("http://www.yourdomain.com/
fileupload.cfm");
request.method = URLRequestMethod.POST;
event.target.upload(request.url);
}
function openHandler(event:Event):void
{
trace("...open...");
}
function completeHandler(event:Event):void
{
trace("...complete...");
}
Per informazioni dettagliate sulla gestione degli errori asincroni, vedere “Risposte a eventi
errore e a errori basati sullo stato” a pagina 288.
■ Le eccezioni non rilevate sono errori generati a cui non corrisponde una logica (come
un’istruzione catch) di risposta. Se l’applicazione genera un errore per il quale non esiste
un’espressione catch appropriata o per il quale non è disponibile un gestore, né al livello
attuale né al superiore, l’errore viene considerato un’eccezione non rilevata.
In fase di runtime, Flash Player ignora intenzionalmente gli errori non rilevati e, se può,
continua a riprodurre il file SWF perché gli utenti non possono necessariamente essere in
grado di risolvere l’errore. Un errore non rilevato che passa sotto silenzio, cioè che viene
ignorato, complica il lavoro delle applicazioni di debug. La versione debugger di Flash
Player risponde agli errori non rilevati terminando lo script corrente e visualizzando
l’errore non rilevato nell’istruzione trace o annotando il messaggio di errore nel file di
registro. Se l’oggetto eccezione è un’istanza della classe Error o di una sua sottoclasse, viene
richiamato il metodo getStackTrace() e le informazioni sulla traccia di stack vengono
visualizzate anche nell’output dell’istruzione trace o nel file di registro. Per ulteriori
informazioni sull’utilizzo della versione debugger di Flash Player, vedere “Utilizzo della
versione debugger di Flash Player” a pagina 280.
Ogni istruzione catch identifica un tipo di eccezione specifica da gestire. L’istruzione catch
può specificare solo sottoclassi della classe Error. Le istruzioni catch vengono verificate in
sequenza, ma viene eseguita solo la prima istruzione catch che coincide al tipo di errore
generato. In altre parole, se si controlla per prima la classe Error di livello più alto e quindi una
sottoclasse di questa classe, solo la classe Error di livello più alto evidenzierà una
corrispondenza. Il codice seguente illustra questo punto:
try
{
throw new ArgumentError("I am an ArgumentError");
}
catch (error:Error)
{
trace("<Error> " + error.message);
}
catch (error:ArgumentError)
{
trace("<ArgumentError> " + error.message);
}
Vari metodi e proprietà dell’API di Flash Player generano errori in fase di runtime se rilevano
errori durante la loro esecuzione. Ad esempio, il metodo close() della classe Sound genera
un errore IOError se il metodo non riesce a chiudere lo streaming audio, come illustrato nel
codice seguente:
var mySound:Sound = new Sound();
try
{
mySound.close();
}
catch (error:IOError)
{
// Error #2029: Per questo oggetto URLStream non è aperto alcun flusso.
}
Poiché si avvale di una gamma più ampia di classi di errore e di errori del compilatore
incorporati, ActionScript 3.0 consente di visualizzare maggiori dettagli sulle operazioni non
eseguite rispetto alle versioni precedenti del programma. Questa novità permette di creare
applicazioni più stabili con procedure di gestione degli errori più efficaci.
Il blocco try nidificato genera un errore ApplicationError personalizzato catturato dal blocco
catch successivo. Questo blocco catch nidificato può provare a gestire l’errore ma, se l’esito è
negativo, genera l’oggetto ApplicationError diretto al blocco try..catch.
File Descrizione
CustomErrors.mxml Il file principale dell’applicazione in Flash (FLA)
o o Flex (MXML)
CustomErrors.fla
Se l’utente sceglie di annullare lo script facendo clic su Yes nella finestra di avvertenza Alert,
viene generato un errore FatalError e l’applicazione viene interrotta.
Il presente capitolo descrive la sintassi di base per creare le espressioni regolari. Tuttavia, le
espressioni regolari possono presentare notevoli complessità e sfumature. Cercare
informazioni più dettagliate sulle espressioni regolari su Internet o in libreria. Tenere presente
che i vari ambienti di programmazione utilizzano le espressioni regolari in modi diversi.
ActionScript 3.0 implementa le espressioni regolari in base a quanto definito nella specifica
del linguaggio ECMAScript Edizione 3 (ECMA-262).
Sommario
Nozioni di base delle espressioni regolari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306
Sintassi delle espressioni regolari. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 309
Metodi di impiego di espressioni regolari con stringhe . . . . . . . . . . . . . . . . . . . . . . . 327
Esempio: Un parser Wiki . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .328
305
Nozioni di base delle espressioni regolari
Notare che l’inizio e la fine dell’espressione regolare sono indicati dalla barra (/).
La sintassi delle espressioni regolari può essere anche complessa, talvolta addirittura criptica,
come dimostra l’esempio seguente di espressione che cerca un indirizzo e-mail valido:
/([0-9a-zA-Z]+[-._+&])*[0-9a-zA-Z]+@([-0-9a-zA-Z]+[.])+[a-zA-Z]{2,6}/
Generalmente, le espressioni regolari vengono utilizzate per cercare dei modelli all’interno di
stringhe e per sostituire dei caratteri. In questi casi, si crea un oggetto espressione regolare e lo
si usa come parametro di uno dei vari metodi della classe String. I seguenti metodi della classe
String accettano le espressioni regolari come parametri: match(), replace(), search() e
split(). Per ulteriori informazioni su questi metodi, vedere “Ricerca di modelli nelle
stringhe e sostituzione di sottostringhe” a pagina 226.
La classe RegExp comprende i seguenti metodi: test() e exec(). Per ulteriori informazioni,
vedere “Metodi di impiego di espressioni regolari con stringhe” a pagina 327.
L’asterisco (*) è un metacarattere. vale a dire un carattere con un significato speciale all’interno
delle espressioni regolari. L’asterisco è un tipo di metacarattere specifico, definito
quantificatore, che consente di quantificare il numero di ripetizioni di un carattere o gruppo di
caratteri. Per ulteriori informazioni, vedere “Quantificatori” a pagina 316.
Oltre a questo modello, un’espressione regolare può contenere dei flag che specificano la
modalità di ricerca dell’espressione regolare. Ad esempio, nella seguente espressione si usa il
flag i per indicare che l’espressione regolare cerca indistintamente le maiuscole e le minuscole
nelle stringhe:
/ABC\d*/i
Per includere una barra all’interno di un’espressione regolare che usa le barre come
delimitatori, è necessario anteporre alla barra il carattere escape barra rovesciata (\).
Ad esempio, la seguente espressione regolare definisce il modello 1/2:
var pattern:RegExp = /1\/2/;
Per includere delle virgolette doppie all’interno di un’espressione regolare definita mediante la
funzione di costruzione new, è necessario aggiungere il carattere escape barra rovesciata (\)
prima delle virgolette (come si fa per definire un valore letterale di stringa). Ad esempio, le
seguenti espressioni letterali definiscono il modello eat at "joe’s":
var pattern1:RegExp = new RegExp("eat at \"joe's\"", "");
var pattern2:RegExp = new RegExp('eat at "joe\'s"', "");
Non utilizzare il carattere escape barra rovesciata con virgolette doppie all’interno di
espressioni regolari definite usando le barre come delimitatori. Analogamente, non usare il
carattere escape con barre all’interno di espressioni regolari definite mediante la funzione di
costruzione new. Le seguenti espressioni regolari si equivalgono e definiscono il modello 1/2
"joe’s":
var pattern1:RegExp = /1\/2 "joe's"/;
var pattern2:RegExp = new RegExp("1/2 \"joe's\"", "");
var pattern3:RegExp = new RegExp('1/2 "joe\'s"', '');
In questo caso è necessario digitare la barra rovesciata due volte perché il primo parametro del
metodo di costruzione RegExp() è una stringa e nel valore letterale di una stringa è necessario
digitare una barra rovesciata due volte affinché venga riconosciuta come singolo carattere di
barra rovesciata.
Le sezioni seguenti descrivono la sintassi per la definizione dei modelli delle espressioni
regolari.
Per ulteriori informazioni sui flag, vedere “Flag e proprietà” a pagina 322.
Tuttavia, ci sono dei caratteri speciali, definiti metacaratteri, che hanno un significato speciale
all’interno delle espressioni regolari:
^ $ \ . * + ? ( ) [ ] { } |
L’espressione regolare dell’esempio seguente cerca la lettera A seguita da zero o più istanze
della lettera B (il metacarattere asterisco indica la ripetizione), seguita dalla lettera C:
/AB*C/
Metacarattere Descrizione
^ (accento Corrisponde all’inizio della stringa. Se si imposta anche il flag m
circonflesso) (multiline), l’accento circonflesso corrisponde anche all’inizio di una
riga (vedere “Flag m (multiline)” a pagina 324). Si noti che quando viene
usato all’inizio di una classe di caratteri, l’accento circonflesso indica la
negazione, non l’inizio di una stringa. Per ulteriori informazioni, vedere
“Classi di caratteri” a pagina 314.
$ (simbolo del Corrisponde alla fine della stringa. Se si imposta anche il flag m
dollaro) (multiline), $ cerca la corrispondenza anche prima di un carattere nuova
riga (\n). Per ulteriori informazioni, vedere “Flag m (multiline)”
a pagina 324.
| (pipe) Indica due possibilità alternative: può eseguire la ricerca del valore alla
sua sinistra o alla sua destra:
/abc|xyz/ corrisponde a abc o a xyz.
Metasequenza Descrizione
{n} Specifica una quantità numerica o un intervallo di numeri per l’elemento
{n,} precedente:
e /A{27}/ corrisponde al carattere A ripetuto 27 volte.
{n,n} /A{3,}/ corrisponde al carattere A ripetuto 3 o più volte.
/A{3,5}/ corrisponde al carattere A ripetuto da 3 a 5 volte.
Per ulteriori informazioni, vedere “Quantificatori” a pagina 316.
Classi di caratteri
Le classi di caratteri permettono di specificare una serie di caratteri nelle espressioni regolari.
Racchiudere le classi di caratteri tra parentesi angolari ( [ e ] ). Ad esempio, la seguente
espressione regolare definisce una classe di caratteri che corrisponde a bag, beg, big, bog
o bug:
/b[aeiou]g/
Per mantenere il significato letterale dei seguenti caratteri, vale a dire per non utilizzarli come
metacaratteri, anteporre al carattere la barra rovesciata (il carattere escape). Ad esempio, la
seguente espressione regolare comprende una classe di caratteri che corrisponde a uno dei
quattro simboli ($, \, ] o -):
/[$\\\]\-]/
Le altre metasequenze e gli altri metacaratteri delle espressioni regolari vengono trattati come
caratteri normali all’interno delle classi di caratteri.
In alternativa, è possibile specificare un intervallo per valore ASCII usando il codice del
carattere ASCII \xnn. La classe di caratteri dell’esempio seguente corrisponde a qualsiasi
carattere del set di caratteri estesi ASCII (come é e ê):
/[\x80-\x9A]/
Per utilizzare l’accento circonflesso (^) per indicare una negazione è necessario scriverlo
all’inizio della classe di caratteri. In caso contrario, l’accento circonflesso mantiene il suo
valore letterale e viene aggiunto come normale carattere della classe. La classe di caratteri
dell’esempio seguente corrisponde a qualsiasi simbolo, accento circonflesso compreso:
/[!.,#+*%$&^]/
Quantificatori
I quantificatori consentono di specificare ripetizioni di caratteri singoli o di sequenze di
caratteri all’interno dei modelli, come illustrato di seguito:
Metacarattere Descrizione
quantificatore
* (asterisco) Corrisponde a una ripetizione di zero o più volte del carattere
precedente.
Per impostazione predefinita, le espressioni regolari agiscono in modo greedy, vale a dire che
ogni porzione di modello dell’espressione regolare (come .*) cerca una corrispondenza con
quanti più caratteri possibili nella stringa prima di lasciare il posto alla porzione successiva
dell’espressione. Si consideri, ad esempio, l’espressione regolare e la stringa seguenti:
var pattern:RegExp = /<p>.*<\/p>/;
str:String = "<p>Paragraph 1</p> <p>Paragraph 2</p>";
Supponiamo, tuttavia, che si desideri individuare una corrispondenza solo per un gruppo
<p>...</p>. Per ottenere questo risultato, procedere come segue:
<p>Paragraph 1</p>
re = /<p>.*<\/p>/s;
trace(str.match(re));
// output: <p>Test
// Multiline</p>
Per definire gruppi allo scopo di restringere l’area di validità del carattere | si possono usare
parentesi. La seguente espressione regolare corrisponde a cat seguito da nap o da nip:
var pattern:RegExp = /cat(nap|nip)/;
Gruppi
Per specificare un gruppo all’interno di un’espressione regolare si possono usare le parentesi,
come nell’esempio seguente:
/class-(\d*)/
pattern = /a\d+/;
// corrisponde al carattere a seguito da
// una o più cifre
pattern = /a[123]{1,3}/;
// corrisponde al carattere a seguito da
// da una a tre occorrenze di 1, 2 o 3
pattern = /(a\d)+/;
// corrisponde a una o a più occorrenze del carattere a seguito da
// una cifra, come in a1a5a8a3
pattern = /ca(t|d)og/;
// corrisponde a catog o a cadog
Inoltre, quando si usano gruppi di cattura, il metodo exec() della classe RegExp class e il
metodo match() della classe String restituiscono sottostringhe che corrispondono ai gruppi di
cattura:
var pattern:RegExp = /(\w+)@(\w+).(\w+)/;
var str:String = "[email protected]";
trace(pattern.exec(str));
// [email protected],bob,example,com
//noncapturing:
var pattern:RegExp = /(\w+)@(\w+).(?:com|org)/;
var str:String = "[email protected]";
trace(pattern.exec(str));
// [email protected],bob,example
Un tipo speciale di gruppo di non cattura è il gruppo lookahead che, a sua volta, si declina in
due tipi: gruppo lookahead positivo e gruppo lookahead negativo.
Per definire un gruppo lookahead positivo, usare (?= e ), che specifica che il sottomodello del
gruppo deve corrispondere alla posizione. Tuttavia, la porzione di stringa che corrisponde al
gruppo lookahead positivo può corrispondere agli altri modelli dell’espressione regolare. Ad
esempio, dal momento che nel frammento di codice seguente (?=e) è un gruppo lookahead
positivo, il carattere e individuato può essere individuato anche da porzioni successive
dell’espressione regolare, in questo caso dal gruppo di cattura \w*):
var pattern:RegExp = /sh(?=e)(\w*)/i;
var str:String = "Shelly sells seashells by the seashore";
trace(pattern.exec(str));
// Shelly,elly
Per definire un gruppo lookahead negativo, usare (?! e ) che specificano che il sottomodello
del gruppo non deve corrispondere alla posizione. Ad esempio:
var pattern:RegExp = /sh(?!e)(\w*)/i;
var str:String = "She sells seashells by the seashore";
trace(pattern.exec(str));
// shore,ore
Segue un altro esempio che contiene due gruppi denominati (name e dom):
var emailPattern:RegExp =
/(?P<name>(\w|[_.\-])+)@(?P<dom>((\w|-)+))+\.\w{2,4}+/;
var address:String = "[email protected]";
var result:Array = emailPattern.exec(address);
trace(result.name); // bob
trace(result.dom); // esempio
NO T A
I gruppi denominati non fanno parte della specifica del linguaggio ECMAScript. Sono
una funzione speciale di ActionScript 3.0.
Flag e proprietà
La tabella seguente elenca i cinque flag che si possono impostare per le espressioni regolari.
È possibile accedere a ogni flag come proprietà dell’oggetto espressione regolare.
Si noti che le proprietà sono di sola lettura. Si possono impostare i flag (g, i, m, s, x) quando
si imposta la variabile di un’espressione regolare come segue:
var re:RegExp = /abc/gimsx;
Per impostazione predefinita, a meno che non siano stati specificati nella dichiarazione
dell’espressione regolare, i flag non sono impostati e le proprietà corrispondenti sono
impostate su false.
Inoltre, esistono altre due proprietà di un’espressione regolare:
■ La proprietà lastIndex specifica la posizione di indice nella stringa da usare per la
chiamata successiva del metodo exec() o test() dell’espressione regolare.
■ La proprietà source specifica la stringa che definisce la porzione modello dell’espressione
regolare.
Flag g (global)
Se il flag g (global) non è presente, l’espressione regolare ricerca una sola corrispondenza.
Ad esempio, se il flag g non viene impostato nell’espressione regolare, il metodo
String.match() restituisce una sola sottostringa corrispondente:
var str:String = "she sells seashells by the seashore.";
var pattern:RegExp = /sh\w*/;
trace(str.match(pattern)) // output: she
Flag i (ignoreCase)
Per impostazione predefinita, le corrispondenze cercate dalle espressioni regolari distinguono
tra maiuscole e minuscole. Quando si imposta il flag i (ignoreCase), la distinzione tra
maiuscole e minuscole viene disattivata. Ad esempio, la lettera minuscola s dell’espressione
regolare non rileva la lettera maiuscola S, il primo carattere della stringa:
var str:String = "She sells seashells by the seashore.";
trace(str.search(/sh/)); // output: 13 -- Il primo carattere è escluso
Il flag i sospende la distinzione tra maiuscole e minuscole solo per i caratteri A – Z e a – z, non
per i caratteri del set esteso come É e é.
Flag m (multiline)
Se il flag m (multiline) non è impostato, ^ corrisponde alla posizione iniziale della stringa e $
corrisponde alla posizione finale. Quando il flag m è impostato, i caratteri corrispondono,
rispettivamente, alla posizione iniziale di una riga e alla posizione finale. Si consideri la stringa
seguente, che comprende il carattere nuova riga (\n):
var str:String = "Test\n";
str += "Multiline";
trace(str.match(/^\w*/g)); // Corrisponde a una parola all’inizio
// della stringa.
Si noti che solo il carattere \n indica la fine della riga. I caratteri seguenti non indicano la fine
della riga:
■ Ritorno a capo (\r)
■ Separatore di riga Unicode (\u2028)
■ Separatore di paragrafo Unicode (\u2029)
In questo caso, la corrispondenza riguarda l’intera sottostringa racchiusa tra i tag <p>, che
comprende anche il carattere nuova riga:
<p>Test
Multiline</p>
Flag x (extended)
Le espressioni regolari possono risultare abbastanza oscure, specialmente se contengono molti
metacaratteri e metasequenze. Ad esempio:
/<p(>|(\s*[^>]*>)).*?<\/p>/gi
L’uso del flag x (extended) all’interno di un’espressione regolare permette di aggiungere spazi
bianchi che non vengono considerati come parte del modello. L’espressione regolare
dell’esempio seguente è identica a quella dell’esempio precedente:
/ <p (> | (\s* [^>]* >)) .*? <\/p> /gix
Se il flag global è impostato su false, i metodi exec() e test() non usano né impostano la
proprietà lastIndex.
I metodi match(), replace() e search() della classe String avviano tutte le ricerche
dall’inizio della stringa, indipendentemente dall’impostazione della proprietà lastIndex
dell’espressione regolare usata nella chiamata al metodo. (Tuttavia, il metodo match()
imposta lastIndex su 0.)
È possibile impostare la proprietà lastIndex per regolare la posizione iniziale nella stringa per
la corrispondenza dell’espressione regolare.
Proprietà source
La proprietà source specifica la stringa che definisce la porzione modello dell’espressione
regolare. Ad esempio:
var pattern:RegExp = /foo/gi;
trace(pattern.source); // foo
Metodo test()
Il metodo test() della classe RegExp verifica se la stringa contiene una corrispondenza
dell’espressione regolare, come illustra l’esempio seguente:
var pattern:RegExp = /Class-\w/;
var str = "Class-A";
trace(pattern.test(str)); // output: true
Metodo exec()
Il metodo exec() della classe RegExp verifica se la stringa contiene una corrispondenza
dell’espressione regolare e restituisce un array con:
■ La sottostringa di cui si è trovata la corrispondenza
■ Sottostringhe che contengono corrispondenze ai gruppi parentetici dell’espressione
regolare
L’array comprende anche la proprietà index, che indica la posizione di indice dell’inizio della
corrispondenza nella sottostringa.
Consideriamo l’esempio del codice seguente:
var pattern:RegExp = /\d{3}\-\d{3}-\d{4}/; //Numero di telefono USA
var str:String = "phone: 415-555-1212";
var result:Array = pattern.exec(str);
trace(result.index, " - ", result);
// 7 - 415-555-1212
File Descrizione
WikiEditor.mxml Il file principale dell’applicazione in Flash (FLA)
o o Flex (MXML)
WikiEditor.fla
Si noti che la porzione (.?*) dell’espressione regolare cerca qualsiasi numero di caratteri (*)
tra i due modelli di definizione '''. Il quantificatore ? rende la corrispondenza “lazy”, vale a
dire che la prima corrispondenza trovata per la stringa '''aaa''' bbb '''ccc''' sarà
'''aaa''' e non l’intera stringa (che inizia e finisce con ''').
La prima riga definisce un semplice modello per la ricerca delle stringhe in dollari USA.
Si noti che il carattere $ è preceduto dal carattere di escape barra rovesciata (\).
Sommario
Nozioni di base sulla gestione degli eventi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .336
Novità della gestione degli eventi di ActionScript 3.0 rispetto alle versioni
precedenti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .339
Il flusso di eventi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .342
Oggetti evento. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344
Listener di eventi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
Esempio: Alarm Clock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 359
335
Nozioni di base sulla gestione degli eventi
Novità della gestione degli eventi di ActionScript 3.0 rispetto alle versioni precedenti 339
Gestione degli eventi nelle versioni precedenti di
ActionScript
Le versioni di ActionScript anteriori alla 3.0 mettevano a disposizione dei programmatori
varie modalità di gestione degli eventi:
■ Gestori di eventi on() che venivano inseriti direttamente sulle istanze di Button e
MovieClip
■ Gestori di eventi onClipEvent() che venivano inseriti direttamente sulle istanze di
MovieClip
■ Proprietà della funzione Callback, come XML.onload e Camera.onActivity
■ Listener di eventi da registrare tramite il metodo addListener()
■ La classe UIEventDispatcher che implementava parzialmente il modello eventi DOM.
Ognuno di questi meccanismi presentava dei vantaggi e dei limiti. I gestori di eventi on() e
onClipEvent(), ad esempio, sono facili da usare, ma rendono complicata la gestione dei
progetti completati perché il codice inserito direttamente sui pulsanti e filmati clip diventa
difficile da reperire. Anche le funzioni callback sono di facile implementazione, ma ogni
evento ne supporta solo una. I listener di eventi, d’altro canto, sono difficili da implementare
perché non solo richiedono la creazione dell’oggetto listener e della relativa funzione, ma
anche la registrazione del listener per l’oggetto che genera l’evento. A questo maggiore carico
di lavoro corrisponde, però, la possibilità di creare vari oggetti listener e registrarli tutti per lo
stesso evento.
Lo sviluppo di componenti per ActionScript 2.0 ha generato un ulteriore modello di eventi. Il
nuovo modello, incorporato nella classe UIEventDispatcher, si ispirava alla specifica di eventi
DOM. Gli sviluppatori che hanno dimestichezza con la gestione degli eventi dei componenti
troveranno il passaggio al nuovo modello ideato per ActionScript 3.0 relativamente indolore.
Sfortunatamente, la sintassi usata dai vari modelli di eventi è sovrapponibile per vari aspetti
ma differisce in alcuni punti. Ad esempio, in ActionScript 2.0 alcune proprietà, come
TextField.onChanged, possono essere usate come funzione callback o listener di eventi.
Tuttavia, la sintassi per registrare gli oggetti listener differisce a seconda che si usi una delle sei
classi che supportano i listener o la classe UIEventDispatcher. Per le classi Key, Mouse,
MovieClipLoader, Selection, Stage e TextField si usa il metodo addListener(), ma per la
gestione degli eventi dei componenti si usa il metodo addEventListener().
Un’ulteriore difficoltà introdotta dai vari modelli di gestione degli eventi è che l’area di
validità della funzione di gestione differiva notevolmente a seconda del meccanismo utilizzato.
In altre parole, il significato della parola chiave this non era costante nei vari sistemi di
gestione degli eventi.
Comportamenti predefiniti
Generalmente è compito degli sviluppatori scrivere il codice che attiva la risposta agli eventi.
In alcuni casi, tuttavia, un comportamento è così “naturalmente” associato a un evento che
Flash Player attiva automaticamente il comportamento, a meno che lo sviluppatore non
modifichi il codice in modo da annullarlo. In quanto attivati automaticamente da Flash
Player, questi comportamenti vengono definiti predefiniti.
Ad esempio, quando un utente inserisce un testo in un oggetto TextField, l’aspettativa che il
testo venga visualizzato in quel particolare oggetto TextField è così alta che è sembrato
appropriato impostare questo comportamento come predefinito in Flash Player. Se si desidera
disattivare un comportamento predefinito, è sufficiente annullarlo utilizzando il nuovo
sistema di gestione degli eventi. Quando un utente inserisce un testo in un oggetto TextField,
Flash Player crea un’istanza della classe TextEvent che rappresenti l’input dell’utente. Per
impedire che Flash Player visualizzi il testo nel campo TextField, è necessario accedere a quella
precisa istanza di TextEvent e chiamare il metodo preventDefault() dell’istanza.
Non tutti i comportamenti predefiniti possono essere disattivati. Ad esempio, quando un
utente fa doppio clic su una parola di un oggetto TextField, Flash Player genera un oggetto
MouseEvent. Il comportamento predefinito che viene attivato, e che non può in alcun modo
essere disattivato, prevede che la parola sotto il cursore sia evidenziata.
A molti tipi di oggetto evento non sono stati associati dei comportamenti predefiniti.
Ad esempio, Flash Player invia un oggetto evento connect quando si attiva una connessione di
rete, ma a questo oggetto non è associato nessun comportamento predefinito. La
documentazione API per la classe Event e le sue sottoclassi elenca tutti i tipi di eventi, descrive
il comportamento predefinito associato a ognuno e indica se il comportamento può essere
disattivato.
Novità della gestione degli eventi di ActionScript 3.0 rispetto alle versioni precedenti 341
È importante capire che i comportamenti predefiniti sono associati solo a oggetti evento
inviati da Flash Player mentre non esistono per oggetti evento inviati dal codice tramite
ActionScript. Ad esempio, è consentito usare i metodi della classe EventDispatcher per inviare
un oggetto evento del tipo textInput, ma a tale oggetto non sarà associato un
comportamento predefinito. In altre parole, Flash Player non visualizza un carattere in un
oggetto TextField come risultato di un evento textInput inviato a livello di codice.
Il flusso di eventi
Ogni volta che si verifica un evento, Flash Player invia un oggetto evento. Se il destinatario
dell’evento non fa parte dell’elenco di visualizzazione, Flash Player trasmette l’oggetto evento
direttamente al destinatario dell’evento. Ad esempio, Flash Player invia l’oggetto progress
direttamente a un oggetto URLStream. Se invece il destinatario dell’evento fa parte dell’elenco
di visualizzazione, Flash Player invia l’oggetto evento all’elenco di visualizzazione e l’oggetto
percorre l’elenco di visualizzazione fino ad arrivare al destinatario dell’evento.
Il flusso di eventi descrive il modo in cui l’oggetto evento percorre l’elenco di visualizzazione.
L’elenco di visualizzazione è organizzato come una struttura gerarchica. In cima all’elenco si
trova lo Stage, uno speciale contenitore di oggetti di visualizzazione che funge da radice
dell’elenco di visualizzazione. Lo Stage è rappresentato dalla classe flash.display.Stage ed è
accessibile solo attraverso un oggetto di visualizzazione. Ogni oggetto di visualizzazione è
dotato di una proprietà denominata stage che fa riferimento allo Stage per quella particolare
applicazione.
Stage
Nodo principale
Se un utente fa clic su Child1 Node, Flash Player invia un oggetto evento nel flusso di eventi.
Come dimostra l’immagine seguente, il tragitto dell’oggetto parte da Stage, attraversa Parent
Node e arriva a Child1 Node, per poi ripartire verso Stage attraversando di nuovo Parent
Node e arrestarsi a Stage.
Stage
Fase di Fase di
cattura bubbling
Nodo principale
Fase target
Oggetti evento
Nel nuovo sistema di gestione degli eventi, gli oggetti evento svolgono due funzioni principali.
Innanzi tutto, gli oggetti evento rappresentano veri e propri eventi in quanto ne memorizzano
le proprietà. Secondariamente, gli oggetti evento contengono una serie di metodi che
permettono di manipolare gli oggetti stessi e di influenzare il comportamento del sistema di
gestione degli eventi.
Allo scopo di facilitare l’accesso a tali proprietà e metodi, l’API di Flash Player definisce una
classe Event che funge da classe base per tutti gli oggetti evento. La classe Event definisce una
serie di proprietà e metodi fondamentali comuni a tutti gli oggetti evento.
Alla classe Event sono associate circa una ventina di tipi di evento che sono rappresentati da
costanti della classe Event. Alcune di queste costanti sono indicate nella porzione di codice che
rappresenta la definizione della classe Event:
package flash.events
{
public class Event
{
// costanti della classe
public static const ACTIVATE:String = "activate";
public static const ADDED:String = "added";
// altre costanti omesse per ragioni di spazio
}
}
La proprietà bubbles
Se un oggetto evento partecipa alla fase di bubbling del flusso di eventi significa che l’oggetto
evento viene fatto risalire dal nodo target su fino allo Stage. La proprietà Event.bubbles
registra un valore booleano che indica se l’oggetto evento partecipa alla fase di bubbling.
Dal momento che gli eventi che partecipano alla fase di bubbling partecipano anche alle fasi
di cattura e target, se il valore della proprietà è true, l’oggetto evento partecipa a tutte le tre
fasi. Se il valore è false, l’oggetto evento non partecipa alla fase di bubbling.
Queste costanti corrispondono ai tre valori validi della proprietà eventPhase e concorrono a
rendere il codice più leggibile. Ad esempio, per fare in modo che la funzione myFunc() sia
chiamata solo se il destinatario dell’evento si trova nella fase target, si può usare il codice
seguente per verificare questa condizione:
if (event.eventPhase == EventPhase.AT_TARGET)
{
myFunc();
}
La proprietà target
La proprietà target contiene un riferimento all’oggetto che rappresenta il destinatario
dell’evento. In alcuni casi il destinatario è semplice: quando un microfono diventa attivo, il
destinatario dell’evento è l’oggetto Microphone. Se il destinatario si trova nell’elenco di
visualizzazione, tuttavia, è necessario prendere in considerazione anche la gerarchia dell’elenco
di visualizzazione. Ad esempio, se un utente esegue un clic del mouse in un punto che
comprende più oggetti dell’elenco di visualizzazione sovrapposti, Flash Player sceglie come
destinatario dell’evento l’oggetto più distante dallo Stage.
Nei file SWF particolarmente complessi, in particolare quelli in cui i pulsanti sono
normalmente decorati con piccoli oggetti secondari, la proprietà target spesso può non
essere utilizzabile poiché punterebbe a un oggetto secondario e non al pulsante. Un metodo
comunemente usato in questi casi consiste nell’aggiungere listener di eventi al pulsante e usare
la proprietà currentTarget perché ha la particolarità di puntare al pulsante, mentre la
proprietà target potrebbe puntare a un oggetto secondario del pulsante.
function clickHandler(event:MouseEvent):void
{
trace("clickHandler detected an event of type: " + event.type);
trace("the this keyword refers to: " + this);
}
Quando un utente interagisce con il file SWF facendo clic sul quadrato, Flash Player genera il
seguente output di traccia:
clickHandler detected an event of type: click
the this keyword refers to: [object global]
Si noti che l’oggetto evento viene passato come argomento a clickHandler(). Questo
permette alla funzione listener di analizzare l’oggetto evento. In questo esempio, si usa la
proprietà type dell’oggetto evento per determinare se l’evento è un clic del mouse.
L’esempio verifica anche il valore della parola chiave this. In questo caso, this rappresenta
l’oggetto globale, il che è opportuno perché la funzione è definita al di fuori di qualsiasi classe
predefinita o oggetto.
import flash.display.Sprite;
import flash.events.MouseEvent;
Quando un utente interagisce con il file SWF facendo clic sul quadrato rosso, Flash Player
genera il seguente output di traccia:
clickHandler detected an event of type: click
the this keyword refers to: [object ChildSprite]
function removeEventListener(eventName:String,
listener:Object,
useCapture:Boolean=false):Boolean;
function dispatchEvent(eventObject:Event):Boolean;
function hasEventListener(eventName:String):Boolean;
function willTrigger(eventName:String):Boolean;
}
}
La maggior parte degli eventi errore si basano sulla classe ErrorEvent e in quanto tali sono
configurati con la proprietà text che viene utilizzata per memorizzare il messaggio di errore
visualizzato da Flash Player. Le uniche due eccezioni sono costituite dalle classi StatusEvent e
NetStatusEvent, che sono caratterizzate dalla proprietà level (StatusEvent.level e
NetStatusEvent.info.level). Quando il valore della proprietà level è "error", questi
tipi di evento vengono considerati eventi errore.
Un evento errore non determina l’arresto della riproduzione di un file SWF e genera solo la
visualizzazione di una finestra di dialogo nelle versioni debugger dei plug-in per browser e dei
lettori autonomi, di un messaggio nel pannello Output nel player di creazione e l’aggiunta di
una riga nel file di registro di Adobe Flex Builder 2. Non si manifesta affatto nelle versioni
standard di Flash Player.
File Descrizione
AlarmClockApp.mxml Il file principale dell’applicazione in Flash (FLA)
o o Flex (MXML)
AlarmClockApp.fla
com/example/programmingas3/clock/ Classe che estende la classe SimpleClock
AlarmClock.as aggiungendo la funzionalità sveglia.
/**
* Timer che verrà usato per la sveglia.
*/
public var alarmTimer:Timer;
...
/**
* Crea una nuova istanza di AlarmClock.
*/
public override function initClock(faceSize:Number = 200):void
{
super.initClock(faceSize);
alarmTimer = new Timer(0, 1);
alarmTimer.addEventListener(TimerEvent.TIMER, onAlarm);
}
return alarmTime;
}
Una volta trascorsa la quantità di tempo specificata, alarmTimer invia l’evento timer. Poiché
la classe AlarmClock ha registrato il suo metodo onAlarm() come listener di quell’evento,
quando l’evento timer si verifica, onAlarm() viene chiamato.
/**
* Chiamato quando l’evento timer viene inviato.
*/
public function onAlarm(event:TimerEvent):void
{
trace("Alarm!");
var alarm:AlarmEvent = new AlarmEvent(this.alarmMessage);
this.dispatchEvent(alarm);
}
Un metodo registrato come listener di eventi deve essere definito con l’indicatore appropriato
(cioè, l’insieme di parametri e il tipo restituito del metodo). Per poter essere impostato come
listener dell’evento timer della classe Timer, un metodo deve definire un parametro il cui tipo
di dati è TimerEvent (flash.events.TimerEvent), una sottoclasse della classe Event. Quando
l’istanza di Timer chiama i suoi listener di eventi, passa un’istanza di TimerEvent come
oggetto evento.
Le seguenti righe di codice sono state estratte dal metodo onAlarm() della classe AlarmClock
(riprodotto integralmente in precedenza). Viene chiamato il metodo dispatchEvent()
dell’istanza AlarmClock, che notifica tutti i listener registrati che l’evento alarm dell’istanza di
AlarmClock è stato attivato. Il parametro passato a dispatchEvent() è l’oggetto evento che
viene trasmesso ai metodi del listener. In questo caso, si tratta di un’istanza della classe
AlarmEvent, una sottoclasse di Event creata specificamente per questo esempio.
/**
* La classe Event personalizzata aggiunge una proprietà message alla
classe di base Event.
*/
public class AlarmEvent extends Event
{
/**
* Il nome del nuovo tipo di AlarmEvent.
*/
public static const ALARM:String = "alarm";
/**
* Messaggio di testo che può essere passato a un gestore di eventi
* insieme a questo oggetto evento.
*/
public var message:String;
/**
* Funzione di costruzione.
* @param message Il testo da visualizzare all’attivazione della
sveglia.
*/
public function AlarmEvent(message:String = "ALARM!")
{
super(ALARM);
this.message = message;
}
...
}
Il modo migliore per creare una classe oggetto evento personalizzata consiste nel definire una
classe che estende la classe Event, come illustrato nell’esempio precedente. Per completare la
funzionalità ereditata la classe AlarmEvent definisce la proprietà message che contiene il testo
del messaggio associato all’evento; il valore message viene passato come parametro nella
funzione di costruzione AlarmEvent. La classe AlarmEvent definisce anche la costante ALARM,
che può essere usata come riferimento all’evento specifico (alarm) quando si chiama il
metodo addEventListener() della classe AlarmClock.
Oltre ad aggiungere delle funzionalità personalizzate, ogni sottoclasse di Event deve sostituire
il metodo clone() ereditato come parte della struttura di gestione degli eventi di
ActionScript. In via facoltativa, le sottoclassi di Event possono anche sostituire il metodo
ereditato toString() al fine di includere le proprietà dell’evento personalizzato nel valore
restituito quanto il metodo toString() viene chiamato.
/**
* Restituisce una stringa contenente tutte le proprietà
* dell’istanza corrente.
* @return Una rappresentazione sotto forma di stringa dell’istanza
corrente.
*/
public override function toString():String
{
return formatToString("AlarmEvent", "type", "bubbles", "cancelable",
"eventPhase", "message");
}
Il metodo sostituito clone() deve restituire una nuova istanza della sottoclasse Event
personalizzata con tutte le proprietà personalizzate impostate sull’istanza corrente. Nel
metodo sostituito toString(), il metodo utilità formatToString() (ereditato da Event)
viene usato per fornire una stringa con il nome del tipo personalizzato e i nomi e i valori di
tutte le sue proprietà.
Sommario
Nozioni di base su XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .368
L’approccio di E4X all’elaborazione XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372
Oggetti XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 374
Oggetti XMLList . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377
Inizializzazione delle variabili di XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 378
Assemblaggio e trasformazione di oggetti XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . 380
Lettura delle strutture XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .382
Uso dello spazio dei nomi XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387
Conversione degli oggetti XML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .388
Lettura di documenti XML esterni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
Esempio: Caricamento di dati RSS da Internet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391
367
Nozioni di base su XML
I dati XML possono essere anche più complessi e contenere tag nidificati in altri tag, attributi
e altri componenti strutturali. Ecco un esempio di dati più complessi in formato XML:
<album>
<title>Questions, unanswered</title>
<artist>Steve and the flubberblubs</artist>
<year>1989</year>
<tracks>
<song tracknumber="1" length="4:05">
<title>What do you know?</title>
<artist>Steve and the flubberblubs</artist>
<lastplayed>2006-10-17-08:31</lastplayed>
</song>
<song tracknumber="2" length="3:45">
<title>Who do you know?</title>
<artist>Steve and the flubberblubs</artist>
<lastplayed>2006-10-17-08:35</lastplayed>
</song>
<song tracknumber="3" length="5:14">
<title>When do you know?</title>
<artist>Steve and the flubberblubs</artist>
<lastplayed>2006-10-17-08:39</lastplayed>
</song>
<song tracknumber="4" length="4:19">
<title>Do you know?</title>
<artist>Steve and the flubberblubs</artist>
<lastplayed>2006-10-17-08:44</lastplayed>
</song>
</tracks>
</album>
Ogni elemento è caratterizzato da una serie di tag: il nome dell’elemento racchiuso tra
parentesi angolari (i simboli di minore di/maggiore di). Il tag di apertura, che indica l’inizio
dell’elemento, contiene il nome dell’elemento:
<title>
Il tag di chiusura indica la fine dell’elemento e presenta una barra prima del nome
dell’elemento:
</title>
Gli elementi che non presentano del contenuto possono essere scritti come elementi vuoti.
Nel formato XML, l’elemento:
<lastplayed/>
Tutti gli elementi XML prevedono del contenuto, che può essere un valore singolo, uno o più
elementi XML oppure niente (nel caso di elementi vuoti).
Per operazioni di livello avanzato che comprendono spazi dei nomi XML, ActionScript mette
a disposizione le classi Namespace e QName. Per ulteriori informazioni, vedere “Uso dello
spazio dei nomi XML” a pagina 387.
Oltre alle classi incorporate specifiche per XML, ActionScript 3.0 comprende vari operatori
che attivano funzionalità specifiche per l’accesso ai dati XML e la loro manipolazione.
L’approccio che prevede la gestione dei dati XML tramite queste classi e questi operatori è
conosciuto come ECMAScript for XML (E4X) ed è definito nella specifica ECMA-357
edizione 2.
ActionScript 2.0 prevedeva una classe XML che in ActionScript 3.0 è stata
ridenominata XMLDocument, allo scopo di non creare un conflitto con la classe XML di
ActionScript 3.0 che fa parte di E4X. In ActionScript 3.0, le classi precedenti -
XMLDocument, XMLNode, XMLParser e XMLTag - sono state inserite nel pacchetto
flash.xml per assicurare il supporto retroattivo. Le nuove classi E4X sono classi principali
che per essere utilizzate non richiedono l’importazione di un pacchetto. Il presente
capitolo non approfondisce le classi XML usate da ActionScript 2.0. Per maggiori
dettagli a questo riguardo, consultare il pacchetto flash.xml nella Guida di riferimento al
linguaggio e ai componenti di ActionScript 3.0.
Nonostante accada spesso che le applicazioni carichino i dati XML da un’origine esterna,
come il servizio Web o un feed RSS, per motivi di chiarezza gli esempi presentati in questo
capitolo assegnano valori letterali ai dati XML.
Come illustra la porzione di codice seguente, E4X comprende alcuni operatori intuitivi, come
il punto (.) e l’identificatore di attributi (@) che vengono usati per accedere alle proprietà e
agli attributi XML:
trace(myXML.item[0].menuName); // Output: burger
trace(myXML.item.(@id==2).menuName); // Output: fries
trace(myXML.item.(menuName=="burger").price); // Output: 3.95
Usare il metodo appendChild() per assegnare un nuovo nodo secondario al codice XML,
come illustrato nello snippet di codice seguente:
var newItem:XML =
<item id="3">
<menuName>medium cola</menuName>
<price>1.25</price>
</item>
myXML.appendChild(newItem);
Usare gli operatori @ e . non solo per leggere i dati, ma anche per assegnarli, come illustrato di
seguito:
myXML.item[0].menuName="regular burger";
myXML.item[1].menuName="small fries";
myXML.item[2].menuName="medium cola";
Oggetti XML
Un oggetto XML può rappresentare un elemento, un attributo, un commento, un’istruzione
di elaborazione o un elemento di testo XML.
Gli oggetti XML sono classificati come oggetti con contenuto semplice o contenuto complesso.
Un oggetto XML che comprende nodi secondari è classificato come oggetto con contenuto
complesso. Gli oggetti XML con contenuto semplice sono gli attributi, i commenti, le
istruzioni di elaborazione e i nodi di testo.
Ad esempio, nel seguente oggetto XML è presente contenuto complesso perché comprende
un commento e un’istruzione di elaborazione:
XML.ignoreComments = false;
XML.ignoreProcessingInstructions = false;
var x1:XML =
<order>
<!--Questo è un commento. -->
<?PROC_INSTR sample ?>
<item id='1'>
<menuName>burger</menuName>
<price>3.95</price>
</item>
<item id='2'>
<menuName>fries</menuName>
<price>1.45</price>
</item>
</order>
Come illustra l’esempio seguente, ora è possibile usare i metodi comments() e
processingInstructions() per creare nuovi oggetti XML, un commento e una istruzione
di elaborazione:
var x2:XML = x1.comments()[0];
var x3:XML = x1.processingInstructions()[0];
Metodi XML
I metodi seguenti permettono di eseguire operazioni con la struttura gerarchica degli
oggetti XML:
■ appendChild()
■ child()
■ childIndex()
■ children()
■ descendants()
■ elements()
■ insertChildAfter()
■ insertChildBefore()
■ parent()
■ prependChild()
I metodi seguenti permettono di eseguire operazioni con gli attributi degli oggetti XML:
■ attribute()
■ attributes()
I metodi seguenti permettono di eseguire operazioni con le proprietà degli oggetti XML:
■ hasOwnProperty()
■ propertyIsEnumerable()
■ replace()
■ setChildren()
Per elenco delle proprietà e dei metodi di XML, vedere “Oggetti XML” a pagina 374.
Come illustrato nello snippet di codice seguente, è possibile usare anche la funzione di
costruzione new per creare un’istanza di un oggetto XML partendo da una stringa che
contiene dati XML:
var str:String = "<order><item id='1'><menuName>burger</menuName>"
+ "<price>3.95</price></item></order>";
var myXML:XML = new XML(str);
Per caricare dei dati XML da un URL, usare la classe URLLoader, come illustrato nell’esempio
seguente:
import flash.events.Event;
import flash.net.URLLoader;
import flash.net.URLRequest;
var externalXML:XML;
var loader:URLLoader = new URLLoader();
var request:URLRequest = new URLRequest("xmlFile.xml");
loader.load(request);
loader.addEventListener(Event.COMPLETE, onComplete);
function onComplete(event:Event):void
{
var loader:URLLoader = event.target as URLLoader;
if (loader != null)
{
externalXML = new XML(loader.data);
trace(externalXML.toXMLString());
}
else
{
trace("loader is not a URLLoader!");
}
}
Per leggere i dati XML da una connessione socket, usare la classe XMLSocket. Per ulteriori
informazioni, vedere la voce relativa alla classe XMLSocket nella Guida di riferimento al
linguaggio e ai componenti di ActionScript 3.0.
Come illustrato dall’esempio seguente, è possibile utilizzare anche gli operatori parentesi
graffe ( { e } ) per passare dati in base al riferimento (da altre variabili) durante la costruzione
di oggetti XML:
var ids:Array = [121, 122, 123];
var names:Array = [["Murphy","Pat"], ["Thibaut","Jean"], ["Smith","Vijay"]]
var x:XML = new XML("<employeeList></employeeList>");
x = x.appendChild(newnode)
}
È possibile usare il metodo child() per andare agli elementi secondari con nomi basati su
una variabile o un’espressione, come illustrato nell’esempio seguente:
var myXML:XML =
<order>
<book>
<title>Dictionary</title>
</book>
</order>;
Per accedere a tutti gli attributi di un oggetto XML o XMLList si può usare il carattere jolly *
combinato al simbolo @, come illustrato nel codice seguente:
var employee:XML =
<employee id="6401" code="233">
<lastName>Wu</lastName>
<firstName>Erin</firstName>
</employee>;
trace(employee.@*.toXMLString());
// 6401
// 233
Si noti che per accedere agli attributi è anche possibile utilizzare la sintassi seguente, come
illustrato nell’esempio seguente:
employee.attribute("id")
employee["@id"]
employee.@["id"]
Per evitare questo tipo di errori, è possibile identificare le proprietà per cui esistono attributi o
elementi corrispondenti usando i metodi attribute() e elements(), come nel codice
seguente:
var doc:XML =
<body>
<p id='123'>Hello, <b>Bob</b>.</p>
<p>Hello.</p>
</body>;
trace(doc.p.(attribute('id') == '123'));
trace(doc.p.(elements('b') == 'Bob'));
Inoltre, è possibile utilizzare anche il metodo hasOwnProperty(), come nel codice seguente:
var doc:XML =
<body>
<p id='123'>Hello, <b>Bob</b>.</p>
<p>Hello.</p>
</body>;
trace(doc.p.(hasOwnProperty('@id') && @id == '123'));
trace(doc.p.(hasOwnProperty('b') && b == 'Bob'));
Lo spazio dei nomi è caratterizzato da un prefisso, soap, e da un URI che definisce lo spazio
dei nomi, http://schemas.xmlsoap.org/soap/envelope/.
ActionScript 3.0 contiene la classe Namespace per le operazioni con gli spazi dei nomi XML.
Per l’oggetto XML dell’esempio precedente, è possibile usare la classe Namespace come segue:
var soapNS:Namespace = message.namespace("soap");
trace(soapNS); // Output: http://schemas.xmlsoap.org/soap/envelope/
message.soapNS::Body.wNS::GetWeatherResponse.wNS::tempurature = "78";
La direttiva default xml namespace permette di assegnare uno spazio dei nomi predefinito
agli oggetti XML. Nell’esempio seguente, sia x1 che x2 condividono il medesimo spazio dei
nomi predefinito:
var ns1:Namespace = new Namespace("http://www.example.com/namespaces/");
default xml namespace = ns1;
var x1:XML = <test1 />;
var x2:XML = <test2 />;
trace(myXML.item[0].menuName.toXMLString());
// <menuName>burger</menuName>
trace(myXML.item[0].menuName.toString());
// burger
trace(myXML.item[0].menuName);
// burger
Quando si usa il metodo trace() per le attività di debug del codice, spesso risulta utile usare
il metodo toXMLString() per fare in modo che trace() restituisca dati più completi.
Se nel codice non fosse stata aggiunta la funzione Number(), il codice avrebbe interpretato
l’operatore + come l’operatore di concatenazione di stringhe e il metodo trace() dell’ultima
riga avrebbe generato il valore seguente:
01.003.95
function xmlLoaded(event:Event):void
{
myXML = XML(myLoader.data);
trace("Data loaded.");
}
È inoltre possibile usare la classe XMLSocket per impostare una connessione socket XML
asincrona con un server. Per ulteriori informazioni, consultare la Guida di riferimento al
linguaggio e ai componenti di ActionScript 3.0 e
<item>
<title>
Short Term Forecast - Taiya Inlet, Klondike Highway (Alaska)
</title>
<link>
http://www.nws.noaa.gov/alerts/ak.html#A18.AJKNK.1900
</link>
<description>
Short Term Forecast Issued At: 2005-04-11T19:00:00
Expired At: 2005-04-12T01:00:00 Issuing Weather Forecast Office
Homepage: http://pajk.arh.noaa.gov
</description>
</item>
<item>
<title>
Short Term Forecast - Haines Borough (Alaska)
</title>
<link>
http://www.nws.noaa.gov/alerts/ak.html#AKZ019.AJKNOWAJK.190000
</link>
<description>
Short Term Forecast Issued At: 2005-04-11T19:00:00
Expired At: 2005-04-12T01:00:00 Issuing Weather Forecast Office
Homepage: http://pajk.arh.noaa.gov
</description>
</item>
</channel>
</rss>
File Descrizione
RSSViewer.mxml Il file principale dell’applicazione in Flash (FLA)
o o Flex (MXML)
RSSViewer.fla
Verso l’inizio del metodo, il codice indica lo spazio dei nomi XML predefinito se i dati RSS di
origine comprendono uno spazio dei nomi predefinito:
if (rssXML.namespace("") != undefined)
{
default xml namespace = rssXML.namespace("");
}
Le prime tre righe si limitano a impostare le variabili stringa che rappresentano le proprietà del
titolo, della descrizione e del collegamento della proprietà item dei dati XML. La riga
seguente chiama il metodo buildItemHTML() per ottenere i dati HTML sotto forma di
oggetto XMLList, usando le tre nuove variabili come parametri.
Le prime righe del metodo eliminano lo spazio dei nomi xml predefinito:
default xml namespace = new Namespace();
La direttiva default xml namespace ha un’area di validità a livello di blocco della funzione.
Ciò significa che l’area di validità di questa dichiarazione è il metodo buildItemHTML().
p.appendChild(<br/>);
p.appendChild(link);
body += p;
Questo oggetto XMLList rappresenta dei dati in formato stringa adatti a un campo di testo
HTML di ActionScript.
Il metodo xmlLoaded() usa il valore restituito dal metodo buildItemHTML() e lo converte in
stringa:
XML.prettyPrinting = false;
rssOutput = outXML.toXMLString();
Infine, il metodo xmlLoaded() genera un evento che notifica l’applicazione che i dati sono
stati analizzati e sono disponibili:
dataWritten = new Event("dataWritten", true);
Programmazione degli
elementi visivi
12
La programmazione degli elementi visivi in ActionScript 3.0 consente di lavorare con
elementi visualizzati sullo stage di Adobe Flash Player 9. In questo capitolo vengono descritti i
concetti base del lavoro con gli elementi sullo schermo. Vengono inoltre fornite informazioni
dettagliate sull’organizzazione programmatica degli elementi visivi e sulla creazione di classi
personalizzate per la visualizzazione degli oggetti.
Sommario
Elementi fondamentali della programmazione degli elementi visivi . . . . . . . . . . . 395
Classi di visualizzazione di base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 401
Vantaggi dell’elenco di visualizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403
Operazioni con gli oggetti di visualizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .407
Manipolazione di oggetti di visualizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .422
Mascheratura degli oggetti di visualizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444
Animazione di oggetti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .447
Esempio: SpriteArranger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 454
395
■ Stage
Lo stage è un contenitore di base di oggetti di visualizzazione. Ogni applicazione presenta
un oggetto stage contenente tutti gli oggetti visualizzati sullo schermo. Lo stage è il
contenitore di primo livello e si trova in cima alla gerarchia dell’elenco di visualizzazione:
Stage
Istanza della
classe principale
del file SWF
Oggetto di Contenitore
oggetto di
visualizzazione visualizzazione
Contenitore Oggetto di
oggetto di
visualizzazione visualizzazione
Contenitore
oggetto di
visualizzazione
Contenitore
Oggetto di oggetto di
visualizzazione visualizzazione
Ogni file SWF presenta una classe ActionScript associata, conosciuta come classe principale
del file SWF. Quando Flash Player apre un file SWF in una pagina HTML, Flash Player
richiama la funzione di costruzione per quella classe e l’istanza che viene creata
(che è sempre un tipo di oggetto di visualizzazione) viene aggiunta come elemento
secondario dell’oggetto stage. La classe principale di un file SWF estende sempre la
classe Sprite (Per ulteriori informazioni, vedere “Vantaggi dell’elenco di visualizzazione”
a pagina 403).
Per accedere allo stage è necessario passare dalla proprietà stage di una qualsiasi istanza di
DisplayObject. Per ulteriori informazioni, vedere “Impostazione delle proprietà dello
stage” a pagina 415.
Oggetto TextField.
DisplayObject
MovieClip
Quando si inserisce un qualsiasi elemento visivo sullo stage, tale elemento diventa un
elemento secondario dell’oggetto Stage. Il primo file SWF caricato in un’applicazione
(ad esempio, quello che viene incorporato in una pagina HTML) viene automaticamente
aggiunto come elemento secondario dello stage. Può trattarsi di un oggetto di qualunque tipo
che estende la classe Sprite.
Tutti gli elementi di visualizzazione creati senza usare ActionScript (ad esempio, mediante
l’aggiunta di un tag MXML in Adobe Flex Builder 2 o l’inserimento di un elemento sullo
stage in Flash) vengono inseriti nell’elenco di visualizzazione. Anche se questi oggetti di
visualizzazione non vengono inseriti mediante ActionScript, è possibile accedervi da
ActionScript. Ad esempio, il codice seguente consente di regolare la larghezza di un oggetto
denominato button1 inserito mediante lo strumento di creazione (non mediante
ActionScript):
button1.width = 200;
Forma che
definisce il bordo
del contenitore di
oggetti di
visualizzazione
pictureScreen
Quattro contenitori
di oggetti di
visualizzazione
secondari rispetto
all’oggetto
pictureScreen
Una volta eseguito il codice, gli oggetti di visualizzazione vengono disposti come segue
nell’oggetto DisplayObjectContainer del contenitore. Si osservi il posizionamento degli
oggetti.
container1.addChild(tf1);
container1.addChild(tf2);
container2.addChild(tf1);
Stage
Istanza della
classe principale
del file SWF
Oggetto di Contenitore
oggetto di
visualizzazione visualizzazione
Contenitore Oggetto di
oggetto di
visualizzazione visualizzazione
Contenitore
oggetto di
visualizzazione
Contenitore
Oggetto di oggetto di
visualizzazione visualizzazione
È possibile accedere agli oggetti secondari anche in base al nome. Ogni oggetto di
visualizzazione presenta un nome proprietà; se tale nome non viene assegnato, Flash Player
assegna un valore predefinito, quale "instance1". Ad esempio, il codice seguente mostra
come utilizzare il metodo getChildByName() per accedere a un oggetto di visualizzazione
secondaria denominato "banana loader":
trace(container.getChildByName("banana loader") is Loader); // true
Alcune proprietà e metodi della classe Stage non sono disponibili per oggetti di
visualizzazione che non presentano la stessa funzione di sicurezza sandbox del primo file
SWF. Per informazioni dettagliate, vedere “Stage, sicurezza” a pagina 834.
function resizeDisplay(event:Event):void
{
var swfWidth:int = swfStage.stageWidth;
var swfHeight:int = swfStage.stageHeight;
swfStage.addEventListener(Event.RESIZE, resizeDisplay);
Inoltre, un utente può scegliere di lasciare attiva la modalità a schermo intero e passare a
un’altra finestra di visualizzazione oppure utilizzare una delle varie combinazioni di tasti
disponibili: tasto Esc (tutte le piattaforme), Ctrl-W (Windows), Command-W (Mac) o Alt-F4
(Windows).
function fullScreenRedraw(event:FullScreenEvent):void
{
if (event.fullScreen)
{
// Rimuove i campi di testo di input.
// Aggiunge un pulsante che chiude la modalità a schermo intero.
}
else
{
// Riaggiunge i campi di testo di input.
// Rimuove il pulsante che chiude la modalità a schermo intero.
}
}
mySprite.stage.addEventListener(FullScreenEvent.FULL_SCREEN,
fullScreenRedraw);
Come illustrato dal codice, l’oggetto evento dell’evento fullScreen è un’istanza della classe
flash.events.FullScreenEvent, che include una proprietà fullScreen che indica se la modalità
a schermo intero è attiva (true) o no (false).
Quando si lavora in modalità a schermo intero in ActionScript, tenere presente le seguenti
considerazioni:
■ La modalità a schermo intero può essere avviata mediante ActionScript in risposta a un
clic del mouse (anche con il pulsante destro) o alla pressione di un tasto.
■ Per gli utenti con più monitor, il contenuto SWF si espanderà fino a riempire un solo
monitor. Flash Player impiega una metrica per determinare quale monitor contiene la
porzione più grande di SWF, quindi usa tale monitor per la modalità a schermo intero.
Se si usa JavaScript in una pagina web per generare i tag di incorporamento SWF, è
necessario alterare JavaScript per aggiungere l’attributo/tag allowFullScreen param.
Ad esempio, se la pagina HTML impiega la funzione AC_FL_RunContent() (utilizzata
dalle pagine HTML generate sia da Flex Builder che da Flash), è necessario aggiungere il
parametro allowFullScreen alla chiamata di funzione, come indicato di seguito:
AC_FL_RunContent(
...
'allowFullScreen','true',
...
); //end AC code
Ciò non è applicabile a file SWF eseguiti nel lettore autonomo Flash Player.
■ Tutte le operazioni di tastiera di ActionScript, quali eventi di tastiera e immissione testo
nelle istanze TextFields, vengono disattivate in modalità a schermo intero. La sola
eccezione sono le scelte rapide da tastiera che consentono di chiudere la modalità a
schermo intero.
Vi sono inoltre alcune limitazioni di sicurezza da tenere presente. Tali limitazioni sono
descritte alla sezione “Funzioni di sicurezza sandbox” a pagina 822.
Stage
Fase di Fase di
cattura bubbling
Nodo principale
Fase target
Per ulteriori informazioni, vedere Capitolo 10, “Gestione degli eventi” a pagina 335.
Un dato importante da tenere presente quando si lavora con gli eventi degli oggetti di
visualizzazione è l’effetto sui listener di eventi in relazione alla rimozione automatica degli
oggetti di visualizzazione dalla memoria (garbage collection) quando tali oggetti vengono
rimossi dall’elenco di visualizzazione. Se un oggetto di visualizzazione presenta oggetti
registrati come listener ai propri eventi, tale oggetto di visualizzazione non verrà rimosso dalla
memoria, anche se viene rimosso dall’elenco di visualizzazione, in quanto presenta riferimenti
a tali oggetti listener. Per ulteriori informazioni, vedere “Gestione dei listener di eventi”
a pagina 354.
Manipolazione di oggetti di
visualizzazione
Indipendentemente dal tipo di oggetto di visualizzazione che si decide di utilizzare, vi sono
una serie di manipolazioni comuni a tutti gli oggetti quali elementi visualizzati sullo schermo.
Ad esempio, tutti gli oggetti di visualizzazione possono essere collocati sullo schermo, spostati
avanti o indietro nell’ordine di impilamento, ridimensionati, ruotati e così via. Poiché tutti gli
oggetti di visualizzazione ereditano queste funzionalità dalla loro classe base comune
(DisplayObject), tali funzionalità si comportano allo stesso modo sia che si stia manipolando
un’istanza di TextField, Video, Shape o di qualsiasi altro oggetto. Nelle sezioni che seguono
sono illustrate alcune di queste manipolazioni comuni a tutti gli oggetti di visualizzazione.
import flash.events.MouseEvent;
square.addEventListener(MouseEvent.MOUSE_DOWN, startDragging);
square.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
Come conseguenza del fatto che un solo oggetto per volta può essere trascinato con il metodo
startDrag(), il metodo stopDrag() può essere chiamato per bloccare qualsiasi oggetto di
visualizzazione in fase di trascinamento.
Se è necessario trascinare più di un oggetto di visualizzazione o per evitare conflitti quando
più di un oggetto può potenzialmente usare il metodo startDrag(), si consiglia di utilizzare
la tecnica di inseguimento del mouse per ottenere l’effetto di trascinamento. Con questa
tecnica, quando il pulsante del mouse viene premuto, una funzione viene registrata come
listener dell’evento mouseMove sullo stage. Tale funzione, che in seguito verrà chiamata ogni
volta che il mouse si muove, provoca lo spostamento dell’oggetto trascinato in corrispondenza
delle coordinate x, y del mouse. Quando il pulsante del mouse viene rilasciato, la registrazione
della funzione come listener viene annullata, in modo che la funzione non venga più chiamata
a ogni movimento del mouse e l’oggetto cessi di seguire il cursore. Il codice seguente illustra
tale tecnica:
// Questo codice consente di creare un’interazione di trascinamento della
// selezione mediante inseguimento del mouse. circle è un oggetto
// DisplayObject (ad es. un’istanza di MovieClip o di Sprite).
import flash.events.MouseEvent;
var offsetX:Number;
var offsetY:Number;
// Questa funzione viene chiamata ogni volta che il mouse viene spostato,
// fino a quando il pulsante del mouse resta premuto.
function dragCircle(event:MouseEvent):void
{
// Sposta il cerchio nella posizione del cursore, mantenendo
// lo scarto tra la posizione del cursore e
// la posizione dell’oggetto trascinato.
circle.x = event.stageX - offsetX;
circle.y = event.stageY - offsetY;
circle.addEventListener(MouseEvent.MOUSE_DOWN, startDragging);
circle.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
import flash.display.DisplayObject;
import flash.events.MouseEvent;
var offsetX:Number;
var offsetY:Number;
var draggedObject:DisplayObject;
// Questa funzione viene chiamata ogni volta che il mouse viene spostato,
// fino a quando il pulsante del mouse resta premuto.
function dragObject(event:MouseEvent):void
{
// Sposta l’oggetto trascinato nella posizione del cursore, mantenendo
// lo scarto tra la posizione del cursore e la posizione
// dell’oggetto trascinato.
draggedObject.x = event.stageX - offsetX;
draggedObject.y = event.stageY - offsetY;
circle.addEventListener(MouseEvent.MOUSE_DOWN, startDragging);
circle.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
square.addEventListener(MouseEvent.MOUSE_DOWN, startDragging);
square.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
Per estendere ulteriormente l’effetto, come nel caso di un gioco in cui gettoni o carte vengono
spostati da una pila a un’altra, è possibile inserire l’oggetto trascinato nell’elenco di
visualizzazione dello stage quando viene “raccolto”, quindi inserirlo in un altro elenco di
visualizzazione (ad es. quello della “pila” dove viene depositato) al momento del rilascio del
pulsante del mouse.
Infine, per migliorare l’effetto, è possibile applicare un filtro ombra esterna all’oggetto di
visualizzazione quando viene selezionato mediante clic del mouse (all’inizio del
trascinamento) per poi rimuoverlo quando l’oggetto viene rilasciato. Per ulteriori informazioni
sull’uso del filtro ombra esterna e di altri filtri per gli oggetti di visualizzazione in
ActionScript, vedere Capitolo 15, “Filtraggio degli oggetti di visualizzazione” a pagina 501.
up.addEventListener(MouseEvent.CLICK, scrollUp);
down.addEventListener(MouseEvent.CLICK, scrollDown);
Le variazioni delle dimensioni non sono proporzionali. In altre parole, se si modifica il valore
height di un quadrato senza modificare il valore width, le proporzioni della figura non
verranno mantenute e il quadrato si trasformerà in un rettangolo. Per effettuare modifiche
relative alle dimensioni di un oggetto di visualizzazione, è possibile impostare i valori delle
proprietà scaleX e scaleY per ridimensionare l’oggetto, invece di impostare le proprietà
width e height. Ad esempio, il codice seguente consente di modificare la proprietà width
dell’oggetto denominato square, quindi di alterare la scala verticale (scaleY) per farla
corrispondere a quella orizzontale, in modo da mantenere le corrette proporzioni dell’oggetto.
// Modifica direttamente width.
square.width = 150;
Tuttavia, in questo caso, sarebbe preferibile poter controllare la modifica in scala e indicare le
aree da modificare (i lati paralleli e il centro) e le aree da non modificare (gli angoli), in modo
da non provocare una distorsione dell’oggetto.
Di conseguenza, quando si crea un oggetto di visualizzazione, se si desidera che una parte del
suo contenuto non subisca modifiche in scala, è necessario posizionare le linee divisorie della
griglia della modifica in scala a 9 porzioni in modo che il contenuto da non modificare si trovi
in uno o più dei quattro rettangoli agli angoli.
In ActionScript, se si imposta un valore per la proprietà scale9Grid di un oggetto di
visualizzazione, viene attivata la modifica in scala a 9 porzioni per tale oggetto e viene definita
la dimensione dei rettangoli che formano la griglia. È necessario utilizzare un’istanza della
classe Rectangle come valore per la proprietà scale9Grid, come indicato di seguito:
myButton.scale9Grid = new Rectangle(32, 27, 71, 64);
In questo caso, quando il pulsante viene modificato in scala, gli angoli smussati non verranno
allungati o compressi, mentre tutte le altre parti verranno modificate per adattarsi al
ridimensionamento.
myButton.width = 131;
myButton.height = 106;
myButton.width = 73;
myButton.height = 69;
myButton.width = 54;
myButton.height = 141;
Può accadere che, dopo aver impostato la proprietà cacheAsBitmap su true, l’istanza
dell’oggetto di visualizzazione esegua automaticamente l’aggancio ai pixel su coordinate intere.
Quando si prova il file SWF, si può notare che il rendering delle animazioni vettoriali
complesse viene eseguito più velocemente.
Se si verifica una delle condizioni elencate di seguito, la superficie (bitmap memorizzata nella
cache) non viene creata anche se cacheAsBitmap è impostata su true:
■ La larghezza o l’altezza della bitmap è superiore a 2880 pixel.
■ La bitmap non viene assegnata (a causa di errore di memoria esaurita).
Ovviamente, questo codice avrebbe più senso se venisse utilizzato con uno stage che presenta
uno sfondo rosso uniforme. Su uno sfondo colorato diverso, verrebbe invece specificato tale
colore. Ad esempio, in un file SWF con sfondo bianco, la proprietà opaqueBackground
verrebbe molto probabilmente impostata su 0xFFFFFF o su bianco puro.
// Salvare la modifica.
myDisplayObject.transform.colorTransform = colorInfo;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
blueBtn.addEventListener(MouseEvent.CLICK, makeBlue);
loader.addEventListener(MouseEvent.MOUSE_MOVE, adjustColor);
L’oggetto di visualizzazione mascherato verrà rivelato sotto tutte le aree opache (non trasparenti)
dell’oggetto di visualizzazione che agisce da maschera. Ad esempio, il codice seguente crea
un’istanza di Shape contenente un quadrato rosso di 100 per 100 pixel e un’istanza di Sprite
contenente un cerchio blu con un raggio di 25 pixel. Se si fa clic sul cerchio, esso viene
impostato come maschera del quadrato, in modo che la sola parte visibile di quest’ultimo sia la
parte coperta dall’area piena del cerchio. In altre parole, risulterà visibile solo un cerchio rosso.
// Si presuppone che questo codice venga eseguito all’interno di
// un contenitore di oggetti di visualizzazione
// quale un’istanza di MovieClip o di Sprite.
import flash.display.Shape;
circle.addEventListener(MouseEvent.CLICK, maskSquare);
Non è possibile utilizzare una maschera per mascherarne un’altra, né impostare la proprietà
alpha di un oggetto di visualizzazione utilizzato come maschera. In un oggetto di
visualizzazione impostato come maschera vengono utilizzati solo i riempimenti, mentre i tratti
vengono ignorati.
import flash.display.GradientType;
import flash.display.Loader;
import flash.display.Sprite;
import flash.geom.Matrix;
import flash.net.URLRequest;
Animazione di oggetti
Si definisce animazione il processo di mettere qualcosa in movimento, oppure di modificare
qualcosa in un determinato arco di tempo. L’animazione con script è una parte fondamentale
dei video giochi e viene spesso utilizzata per aggiungere un tocco di ricercatezza e utili
indicazioni di interazione ad altre applicazioni.
L’idea fondamentale alla base dell’animazione con script è il verificarsi di un cambiamento
suddiviso in incrementi lungo un intervallo temporale. In ActionScript, rendere un processo
ripetitivo è facile, grazie a una comune istruzione ciclica. Tuttavia, un ciclo deve eseguire tutte
le sue iterazioni prima di aggiornare lo schermo. Per creare un’animazione mediante script, è
necessario scrivere un codice ActionScript che consenta di eseguire alcune azioni in modo
ripetuto nel tempo, così come di aggiornare lo schermo ogni volta che tale script viene
eseguito.
Ad esempio, si immagini di creare una semplice animazione, quale una palla che attraversa lo
schermo. ActionScript include un semplice meccanismo che consente di tenere traccia del
passaggio del tempo e di aggiornare lo schermo di conseguenza; vale a dire, è possibile scrivere
un codice in grado di fare percorre alla palla una piccola porzione di spazio durante ogni
porzione di tempo, fino a portarla a destinazione. Dopo ogni singolo movimento, lo schermo
viene aggiornato, rendendo visibile un movimento che attraversa lo stage.
Per eseguire un’azione in modo ripetuto nel tempo, è anche possibile utilizzare la classe
Timer. Un’istanza di Timer attiva una notifica evento al trascorre di ogni determinato
intervallo di tempo. È possibile scrivere un codice che consenta di eseguire l’animazione
mediante la gestione dell’evento timer della classe Timer, impostando l’intervallo di
tempo su un valore molto basso (frazioni di secondo). Per ulteriori informazioni sull’uso
della classe Timer, vedere “Controllo degli intervalli di tempo” a pagina 210.
Nell’esempio seguente, viene creata sullo stage un’istanza di Sprite a forma di cerchio
denominata circle. Se si fa clic sul cerchio, viene avviata una sequenza animata mediante
script che provoca la dissolvenza di circle (la sua proprietà alpha viene diminuita) fino a
renderlo completamente trasparente:
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
if (circle.alpha <= 0)
{
circle.removeEventListener(Event.ENTER_FRAME, fadeCircle);
}
}
function startAnimation(event:MouseEvent):void
{
circle.addEventListener(Event.ENTER_FRAME, fadeCircle);
}
circle.addEventListener(MouseEvent.CLICK, startAnimation);
Quando si fa clic sul cerchio, la funzione fadeCircle() viene registrata come listener
dell’evento enterFrame e inizia a essere chiamata a ogni passaggio di fotogramma. Tale
funzione provoca una dissolvenza di circle modificando la sua proprietà alpha; a ogni
fotogramma, la proprietà alpha di circle viene diminuita di 0,05 (5 percento) e lo schermo
viene aggiornato di conseguenza. Alla fine, quando il valore di alpha raggiunge 0 (e circle è
completamente trasparente), la funzione fadeCircle() viene rimossa come listener
dell’evento e l’animazione termina.
Lo stesso codice può essere utilizzato, ad esempio, per creare una vera e propria animazione,
anziché una dissolvenza. Sostituendo la proprietà alpha con una proprietà differente nella
funzione che viene registrata come listener dell’evento enterFrame, tale proprietà risulterà
animata. Ad esempio, se si modifica la riga
circle.alpha -= .05;
la proprietà x risulterà animata e il cerchio verrà spostato verso destra attraverso lo stage.
La condizione che termina l’animazione (vale a dire, l’annullamento della registrazione come
listener di enterFrame) può essere modificata quando viene raggiunta la coordinata x
desiderata.
Una volta caricato il file SWF o l’immagine, è possibile spostare l’oggetto di visualizzazione
caricato in un altro contenitore di oggetti di visualizzazione, come l’oggetto
DisplayObjectContainer di container nell’esempio seguente:
import flash.display.*;
import flash.net.URLRequest;
import flash.events.Event;
var container:Sprite = new Sprite();
addChild(container);
var pictLdr:Loader = new Loader();
var pictURL:String = "banana.jpg"
var pictURLReq:URLRequest = new URLRequest(pictURL);
pictLdr.load(pictURLReq);
pictLdr.contentLoaderInfo.addEventListener(Event.COMPLETE, imgLoaded);
function imgLoaded(event:Event):void
{
container.addChild(pictLdr.content);
}
Stage
Oggetto LoaderInfo
Istanza della
Proprietà
loaderInfo
classe principale
del file SWF
Oggetto caricatore
Proprietà contentLoaderInfo
(Loader)
Oggetto LoaderInfo
function loaded(event:Event):void
{
var content:Sprite = event.target.content;
content.scaleX = 2;
}
Per ulteriori informazioni, vedere Capitolo 10, “Gestione degli eventi” a pagina 335.
Segue un esempio di verifica di un file dei criteri dei domini durante il caricamento di un file
SWF da un altro dominio, al fine di collocare il file nella stessa funzione di sicurezza sandbox
dell’oggetto Loader. Inoltre, il codice inserisce le classi del file SWF caricato nello stesso
dominio applicazione dell’oggetto Loader:
var context:LoaderContext = new LoaderContext();
context.securityDomain = SecurityDomain.currentDomain;
context.applicationDomain = ApplicationDomain.currentDomain;
var urlReq:URLRequest = new URLRequest("http://www.[your_domain_here].com/
library.swf");
var ldr:Loader = new Loader();
ldr.load(urlReq, context);
File Descrizione
SpriteArranger.mxml Il file principale dell’applicazione in Flash (FLA) o
oppure Flex (MXML)
SpriteArranger.fla
Classe DrawingCanvas
La classe DrawingCanvas estende la classe Sprite e questa ereditarietà è definita nella
dichiarazione della classe DrawingCanvas nel modo seguente:
public class DrawingCanvas extends Sprite
La classe GeometricSprite include varie proprietà comuni a tutti gli oggetti GeometricSprite.
Tali proprietà vengono impostate nella funzione di costruzione, in base a una serie di
parametri trasmessi alla funzione. Ad esempio:
this.size = size;
this.lineColor = lColor;
this.fillColor = fColor;
case "Square":
newShape = new SquareSprite(len);
break;
case "Circle":
newShape = new CircleSprite(len);
break;
}
newShape.alpha = 0.8;
this.addChild(newShape);
}
Ciascun metodo della funzione di costruzione richiama il metodo drawShape(), che impiega
la proprietà graphics della classe (ereditata dalla classe Sprite) per disegnare la grafica
vettoriale appropriata. Ad esempio, il metodo drawShape() della classe CircleSprite include il
seguente codice:
this.graphics.clear();
this.graphics.lineStyle(1.0, this.lineColor, 1.0);
this.graphics.beginFill(this.fillColor, 1.0);
var radius:Number = this.size / 2;
this.graphics.drawCircle(radius, radius, radius);
La proprietà shapeType viene impostata sul valore appropriato nel metodo della funzione di
costruzione di ogni sottoclasse di GeometricSprite. Ad esempio, il metodo toString()
potrebbe restituire il seguente valore per un’istanza di CircleSprite recentemente aggiunta
all’istanza DrawingCanvas:
Cerchio di dimensioni 50 a 0, 0
La stringa risultante viene utilizzata per impostare la proprietà text del campo di testo
outputTxt.
Se non si tratta della prima chiamata del metodo onMouseDown(), il metodo si limita a
impostare la proprietà visible della forma selectionIndicator (ereditata dalla classe
DisplayObject) come segue:
this.selectionIndicator.visible = true;
Questo codice consente all’utente di trascinare l’oggetto selezionato per l’area di lavoro, entro
i confini impostati dal rettangolo boundsRect.
Quando il pulsante del mouse viene rilasciato, viene trasmesso l’evento mouseUp. Il metodo
della funzione di costruzione di DrawingCanvas imposta il seguente listener di eventi:
this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
Questo listener di eventi è configurato per l’oggetto DrawingCanvas, anziché per i singoli
oggetti di GeometricSprite, perché se l’oggetto GeometricSprite viene trascinato, potrebbe
finire dietro un altro oggetto di visualizzazione (un altro oggetto GeometricSprite) quando il
mouse viene rilasciato. L’oggetto di visualizzazione in primo piano riceverebbe l’evento di
rilascio del mouse, ma l’oggetto trascinato dall’utente no. L’aggiunta del listener all’oggetto
DrawingCanvas garantisce che l’evento venga sempre gestito.
Il metodo onMouseUp() richiama il metodo onMouseUp() dell’oggetto GeometricSprite che, a
sua volta, richiama il metodo stopDrag() dell’oggetto GeometricSprite.
Sommario
Nozioni di base sulle funzioni geometriche. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .463
Uso degli oggetti Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467
Uso degli oggetti Rectangle. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469
Uso degli oggetti Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .474
Esempio: Applicazione di una trasformazione di matrice a un oggetto di
visualizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 476
463
Tutte le classi che consentono di eseguire funzioni geometriche si basano sul principio che
qualsiasi posizione dello schermo può essere rappresentata come su un piano bidimensionale.
Lo schermo è considerato un grafico con un asse orizzontale (x) e un asse verticale (y).
Qualsiasi punto dello schermo può essere rappresentato da una coppia di valori x e y, cioè da
due coordinate.
Ogni oggetto di visualizzazione, Stage incluso, è dotato del proprio spazio di coordinate,
sostanzialmente un proprio grafico in cui segnare la posizione degli oggetti di visualizzazione
di livello secondario, i disegni e così via. Generalmente, l’origine, cioè il punto con coordinate
0, 0 dove si incontrano i due assi, corrisponde all’angolo superiore sinistro dell’oggetto di
visualizzazione. Questi vale sempre per lo Stage, ma può variare per altri oggetti di
visualizzazione. Come in tutti i normali sistemi di coordinate bidimensionali, i valori dell’asse
delle x aumentano verso destra e diminuiscono verso sinistra. I punti che si trovano a sinistra
dell’origine sono caratterizzati da una coordinata x negativa. Tuttavia, contrariamente a
quanto avviene nei comuni sistemi di coordinate, in ActionScript i valori sull’asse delle y
aumentano verso la parte inferiore dello schermo e diminuiscono verso la parte superiore.
I valori che si trovano più in alto dell’origine avranno una coordinata y negativa. Dal
momento che l’angolo superiore sinistro dello Stage rappresenta l’origine dello spazio di
coordinate, tutti gli oggetti dello Stage avranno una coordinata x superiore a 0 e inferiore alla
larghezza dello Stage e una coordinata y superiore a 0 e inferiore all’altezza dello Stage.
Per rappresentare singoli punti in uno spazio di coordinate si possono usare istanze della classe
Point. È possibile creare un’istanza di Rectangle per rappresentare una zona rettangolare in
uno spazio di coordinate. Gli utenti avanzati possono usare un’istanza di Matrix per applicare
trasformazioni multiple o complesse a un oggetto di visualizzazione. Molte delle
trasformazioni più semplici, come la rotazione, lo spostamento e la modifica in scala possono
essere applicate direttamente a un oggetto di visualizzazione tramite le proprietà dell’oggetto.
Per ulteriori informazioni sull’applicazione delle trasformazioni tramite le proprietà
dell’oggetto di visualizzazione, vedere “Manipolazione di oggetti di visualizzazione”
a pagina 422.
Come illustra il codice seguente, cambiando la proprietà left o top di un oggetto Rectangle,
il rettangolo si sposta e le proprietà x e y ricalcano i valori delle proprietà left e top,
rispettivamente. Tuttavia, poiché la posizione dell’angolo inferiore sinistro dell’oggetto
Rectangle non viene cambiata, il rettangolo viene ridimensionato.
import flash.geom.Rectangle;
var x1:Number = 0;
var y1:Number = 0;
var width1:Number = 100;
var height1:Number = 50;
var rect1:Rectangle = new Rectangle(x1, y1, width1, height1);
trace(rect1) // (x=0, y=0, w=100, h=50)
rect1.left = 20;
rect1.top = 30;
trace(rect1); // (x=30, y=20, w=70, h=30)
Il metodo offsetPt() opera in modo simile, con la differenza che accetta come parametro un
oggetto Point e non i valori di spostamento x e y.
Un oggetto Rectangle può essere ridimensionato anche usando il metodo inflate() che
include due parametri: dx e dy. Il parametro dx rappresenta il numero di pixel rispetto al
centro di cui si sposteranno i lati sinistro e destro del rettangolo; il parametro dy rappresenta il
numero di pixel rispetto al centro di cui si sposteranno i lati superiore e inferiore dell’oggetto:
import flash.geom.Rectangle;
var x1:Number = 0;
var y1:Number = 0;
var width1:Number = 100;
var height1:Number = 50;
var rect1:Rectangle = new Rectangle(x1, y1, width1, height1);
trace(rect1) // (x=0, y=0, w=100, h=50)
rect1.inflate(6,4);
trace(rect1); // (x=-6, y=-4, w=112, h=58)
Il metodo inflatePt() opera in modo simile, con la differenza che accetta come parametro
un oggetto Point e non i valori dx e dy.
Usare il metodo intersects() per scoprire se due rettangoli si intersecano. Inoltre, il metodo
intersects() consente di scoprire se un oggetto di visualizzazione si trova in una
determinata area dello Stage. Ad esempio, nel codice seguente si presume che lo spazio di
coordinate del contenitore di oggetto di visualizzazione che contiene l’oggetto circle sia lo
stesso di quello dello Stage. L’esempio illustra come usare il metodo intersects() per
determinare se un oggetto di visualizzazione, circle, si interseca con aree particolari dello
Stage, definite dagli oggetti Rectangle target1 e target2:
import flash.display.*;
import flash.geom.Rectangle;
var circle:Shape = new Shape();
circle.graphics.lineStyle(2, 0xFF0000);
circle.graphics.drawCircle(250, 250, 100);
addChild(circle);
var circleBounds:Rectangle = circle.getBounds(stage);
var target1:Rectangle = new Rectangle(0, 0, 100, 100);
trace(circleBounds.intersects(target1)); // false
var target2:Rectangle = new Rectangle(0, 0, 300, 300);
trace(circleBounds.intersects(target2)); // true
Analogamente, si può usare il metodo intersects() per scoprire se i perimetri dei rettangoli
degli oggetti di visualizzazione si sovrappongono. È possibile usare il metodo getRect() della
classe DisplayObject per includere lo spazio aggiuntivo che i tratti di un oggetto di
visualizzazione potrebbero aggiungere a un’area di contorno.
myDisplayObject.transform.matrix = matrix;
myDisplayObject.transform.matrix = matrix;
La prima riga imposta un oggetto Matrix sulla matrice di trasformazione esistente usata
dall’oggetto di visualizzazione myDisplayObject (la proprietà matrix della proprietà
transformation dell’oggetto di visualizzazione myDisplayObject). In questo modo, i
metodi chiamati per la classe Matrix avranno un effetto cumulativo sulla posizione, la scala e
la rotazione dell’oggetto di visualizzazione.
N OT A
Per ottenere i file dell’applicazione per questo esempio, accedere all’indirizzo www.adobe.com/
go/learn_programmingAS3samples_flash_it. I file dell’applicazione
DisplayObjectTransformer si trovano nella cartella Samples/DisplayObjectTransformer.
L’applicazione comprende i seguenti file:
File Descrizione
DisplayObjectTransformer.mxml Il file principale dell’applicazione in Flash (FLA)
o o Flex (MXML)
DisplayObjectTransformer.fla
Metodo transform()
Il metodo transform() comprende parametri per gli elementi seguenti:
■ sourceMatrix - Matrice di partenza a cui il metodo applica le trasformazioni
■ xScale e yScale - Fattori di scala di x e y
■ dx e dy - Ammontare dello spostamento di x e y, espressi in pixel
■ rotation - Ammontare della rotazione, espresso in gradi
■ skew - Fattore di inclinazione, espresso in percentuale
■ skewType - Direzione dell’inclinazione, può essere destra ("right") o sinistra ("left")
Il valore restituito è la matrice risultante.
Il metodo transform() chiama i seguenti metodi statici della classe:
■ skew()
■ scale()
■ translate()
■ rotate()
Metodo skew()
Il metodo skew() inclina la matrice modificando le proprietà b e c della matrice stessa.
Un parametro facoltativo, unit, stabilisce le unità in cui è definito l’angolo di inclinazione e,
se necessario, il metodo converte il valore angle in radianti:
if (unit == "degrees")
{
angle = Math.PI * 2 * angle / 360;
}
if (unit == "gradients")
{
angle = Math.PI * 2 * angle / 100;
}
Altrimenti, il lato inferiore viene inclinato modificando la proprietà c dell’oggetto Matrix nel
modo seguente:
skewMatrix.c = Math.tan(angle);
L’inclinazione risultante viene applicata alla matrice esistente concatenando le due matrici,
come illustra l’esempio seguente:
sourceMatrix.concat(skewMatrix);
return sourceMatrix;
Metodo scale()
Come illustra l’esempio seguente, il metodo scale() prima modifica il fattore di scala, se
espresso in valore di percentuale, quindi usa il metodo scale() dell’oggetto Matrix:
if (percent)
{
xScale = xScale / 100;
yScale = yScale / 100;
}
sourceMatrix.scale(xScale, yScale);
return sourceMatrix;
Metodo translate()
Il metodo translate() semplicemente applica i fattori di conversione dx e dy chiamando il
metodo translate() dell’oggetto Matrix come segue:
sourceMatrix.translate(dx, dy);
return sourceMatrix;
Metodo rotate()
Il metodo rotate() converte il fattore di rotazione specificato in radianti (se espresso in gradi
o gradienti), quindi chiama il metodo rotate() dell’oggetto Matrix:
if (unit == "degrees")
{
angle = Math.PI * 2 * angle / 360;
}
if (unit == "gradients")
{
angle = Math.PI * 2 * angle / 100;
}
sourceMatrix.rotate(angle);
return sourceMatrix;
L’applicazione quindi applica il valore restituito alla proprietà matrix della proprietà
transform dell’oggetto di visualizzazione, attivando in questo modo la trasformazione:
img.content.transform.matrix = tempMatrix;
Sommario
Nozioni fondamentali sull’uso dell’API di disegno. . . . . . . . . . . . . . . . . . . . . . . . . . . .482
Nozioni fondamentali sulla classe Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .484
Disegno di linee e curve . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .484
Disegno di forme mediante metodi incorporati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .488
Creazione di linee sfumate e riempimenti con gradiente . . . . . . . . . . . . . . . . . . . . . 489
Uso della classe Math con i metodi di disegno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 494
Animazione mediante l’API di disegno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495
Esempio: Algorithmic Visual Generator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 496
481
Nozioni fondamentali sull’uso dell’API di
disegno
Il valore predefinito per il parametro alfa è 1.0 (100%), pertanto è possibile lasciarlo
disattivato se si desidera una linea completamente opaca. Il metodo lineStyle() accetta
anche due parametri aggiuntivi per l’approssimazione dei pixel e la modalità scala; per
ulteriori informazioni sull’utilizzo di questi parametri, vedere la descrizione del metodo
Graphics.lineStyle() nella Guida di riferimento al linguaggio e ai componenti di
ActionScript 3.0.
Per creare una linea sfumata, utilizzare il metodo lineGradientStyle(). Questo metodo
viene descritto in “Creazione di linee sfumate e riempimenti con gradiente” a pagina 489.
Se si desidera creare una forma piena, chiamare il metodo beginFill(),
beginGradientFill() o beginBitmapFill() prima di iniziare a disegnare. Il metodo
beginFill() è il più elementare dei tre e accetta due parametri: il colore di riempimento e
(facoltativamente) un valore alfa per il colore di riempimento. Ad esempio, se si desidera
disegnare una forma con un riempimento uniforme verde, utilizzare il codice seguente
(l’esempio presuppone che si stia disegnando su un oggetto di nome myShape):
myShape.graphics.beginFill(0x00FF00);
this.addChild(triangle);
Disegno di curve
Il metodo curveTo() disegna una curva Bézier quadratica. Viene disegnato un arco che
collega due punti (definiti punti di ancoraggio) piegandosi verso un terzo punto (definito
punto di controllo). L’oggetto Graphics utilizza la posizione di disegno corrente come primo
punto di ancoraggio. Quando si chiama il metodo curveTo(), si passano quattro parametri:
le coordinate x e y del punto di controllo, seguite dalle coordinate x e y del secondo punto di
ancoraggio. Ad esempio, il codice seguente disegna una curva che inizia nel punto 100, 100 e
termina nel punto 200, 200. Dal momento che il punto di controllo si trova nel punto 175,
125, si ottiene una curva che si sposta verso destra e successivamente verso il basso:
myShape.graphics.moveTo(100, 100);
myShape.graphics.curveTo(175, 125, 200, 200);
L’esempio seguente disegna degli oggetti circolari rossi e verdi con una larghezza e un’altezza di
100 pixel. Si noti che a causa della natura dell’equazione quadratica di Bézier, non si tratta di
cerchi perfetti:
var size:uint = 100;
var roundObject:Shape = new Shape();
this.addChild(roundObject);
Si noti che l’oggetto TextField compare sopra il cerchio disegnato con l’oggetto Graphics.
width = 100;
height = 100;
rotation = 0;
tx = 0;
ty = 0;
width = 100;
height = 100;
rotation = Math.PI/4; // 45°
tx = 0;
ty = 0;
width = 100;
height = 100;
rotation = Math.PI/2; // 90°
tx = 0;
ty = 0;
Gli esempi seguenti illustrano gli effetti su un gradiente lineare verde-blu in cui i parametri
rotation, tx e ty del metodo createGradientBox() differiscono come indicato e tutte le
altre impostazioni rimangono invariate:
width = 50;
height = 100;
rotation = 0;
tx = 0;
ty = 0;
width = 50;
height = 100;
rotation = 0
tx = 50;
ty = 0;
width = 100;
height = 50;
rotation = Math.PI/2; // 90°
tx = 0;
ty = 50;
width = 50;
height = 100;
rotation = 0;
tx = 25;
ty = 0;
Si noti che la larghezza e l’altezza del riempimento con gradiente vengono determinate dalla
larghezza e dall’altezza della matrice del gradiente anziché dalla larghezza o dall’altezza
disegnate mediante l’oggetto Graphics. Quando si disegna mediante l’oggetto Graphics, si
disegna ciò che esiste in corrispondenza di tali coordinate nella matrice del gradiente. Anche
se si utilizza uno dei metodi shape di un oggetto Graphics come drawRect(), il gradiente non
si allunga fino a coprire le dimensioni della forma che si sta disegnando: le dimensioni del
gradiente devono essere specificate nella matrice del gradiente.
L’esempio seguente illustra la differenza visiva tra le dimensioni della matrice del gradiente e le
dimensioni del disegno vero e proprio:
var myShape:Shape = new Shape();
var gradientBoxMatrix:Matrix = new Matrix();
gradientBoxMatrix.createGradientBox(100, 40, 0, 0, 0);
myShape.graphics.beginGradientFill(GradientType.LINEAR, [0xFF0000,
0x00FF00, 0x0000FF], [1, 1, 1], [0, 128, 255], gradientBoxMatrix);
myShape.graphics.drawRect(0, 0, 50, 40);
myShape.graphics.drawRect(0, 50, 100, 40);
myShape.graphics.drawRect(0, 100, 150, 40);
myShape.graphics.endFill();
this.addChild(myShape);
Questo codice disegna tre gradienti con lo stesso stile di riempimento, specificato con una
distribuzione uniforme di rosso, verde e blu. I gradienti vengono disegnati mediante il metodo
drawRect() con larghezze di rispettivamente di 50, 100 e 150 pixel. La matrice del gradiente
specificata nel metodo beginGradientFill() viene creata con una larghezza di 100 pixel.
Ciò significa che il primo gradiente comprende solo metà dello spettro del gradiente, il
secondo lo comprende tutto e il terzo lo comprende tutto e ha 50 pixel aggiuntivi di blu che si
estendono verso destra.
Per ulteriori informazioni sulla classe Matrix, vedere “Uso degli oggetti Matrix” a pagina 474.
var i:uint;
for(i = 1; i < stage.stageWidth; i++)
{
var sinPosY:Number = Math.sin(i / waveStretcher) * waveMultiplier;
var cosPosY:Number = Math.cos(i / waveStretcher) * waveMultiplier;
graphics.beginFill(sinWaveColor);
graphics.drawRect(i, sinWavePosition + sinPosY, 2, 2);
graphics.beginFill(cosWaveColor);
graphics.drawRect(i, cosWavePosition + cosPosY, 2, 2);
}
var currentDegrees:Number = 0;
var radius:Number = 40;
var satelliteRadius:Number = 6;
function doEveryFrame(event:Event):void
{
currentDegrees += 4;
var radians:Number = getRadians(currentDegrees);
var posX:Number = Math.sin(radians) * radius;
var posY:Number = Math.cos(radians) * radius;
satellite.graphics.clear();
satellite.graphics.beginFill(0);
satellite.graphics.drawCircle(posX, posY, satelliteRadius);
}
function getRadians(degrees:Number):Number
{
return degrees * Math.PI / 180;
}
File Descrizione
AlgorithmicVisualGenerator.fla Il file dell’applicazione principale in Flash (FLA).
Sommario
Elementi fondamentali del filtraggio degli oggetti di visualizzazione . . . . . . . . . . . 501
Creazione e applicazione di filtri . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
Filtri di visualizzazione disponibili . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509
Esempio: Filter Workbench . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .528
501
Operazioni di filtraggio comuni
L’uso dei filtri in ActionScript consente di effettuare le operazioni descritte di seguito:
■ Creazione di un filtro
■ Applicazione di un filtro a un oggetto di visualizzazione
■ Applicazione di un filtro ai dati immagine in un’istanza BitmapData
■ Rimozione dei filtri da un oggetto
■ Creazione di vari effetti filtro, quali:
■ Bagliore
■ Sfocatura
■ Ombra esterna
■ Precisione
■ Spostamento
■ Rilevamento dei bordi
■ Rilievi
■ e altri effetti
Applicazione di un filtro
Una volta creato un oggetto filtro, è possibile applicarlo a un oggetto di visualizzazione o a un
oggetto BitmapData; il modo in cui viene applicato dipende dall’oggetto di destinazione.
Quando si crea l’array che contiene i filtri, è possibile crearlo mediante la funzione di
costruzione new Array() (come mostrato negli esempi precedenti) oppure è possibile
utilizzare la sintassi letterale di Array, racchiudendo i filtri tra parentesi quadre ( [] ).
Ad esempio, la riga di codice seguente:
var filters:Array = new Array(dropShadow, blur);
ha lo stesso effetto della riga di codice seguente:
var filters:Array = [dropShadow, blur];
Se si applicano più filtri agli oggetti di visualizzazione, vengono applicati in modo cumulativo
e in sequenza. Ad esempio, se un array filters contiene due elementi, un filtro di smussatura
aggiunto per primo e un filtro ombra esterna aggiunto per secondo, il filtro ombra esterno
viene applicato sia al filtro smussatura che all’oggetto di visualizzazione. Ciò avviene in virtù
del fatto che il filtro ombra esterna occupa la seconda posizione nell’array filters. Se si desidera
applicare i filtri in un modo non cumulativo, è necessario applicare ogni filtro a una nuova
copia dell’oggetto di visualizzazione.
Se si assegnano solo pochi filtri a un oggetto di visualizzazione, è possibile creare l’istanza del
filtro e assegnarla all’oggetto in una sola istruzione. Ad esempio, la riga di codice seguente
applica un filtro sfocatura a un oggetto di visualizzazione denominato myDisplayObject:
myDisplayObject.filters = [new BlurFilter()];
Il codice precedente crea un’istanza Array mediante la sintassi letterale di Array (parentesi
quadre), crea una nuova istanza BlurFilter come elemento dell’Array e assegna tale Array alla
proprietà filters dell’oggetto di visualizzazione denominato myDisplayObject.
Se sono stati applicati più filtri a un oggetto e si desidera rimuovere solo un filtro, è necessario
eseguire diverse operazioni per modificare l’array della proprietà filters. Per ulteriori
informazioni, vedere “Modifica dei filtri in fase di runtime” a pagina 507.
function addFilters(event:MouseEvent):void
{
// Crea una copia dell’array filters.
var filtersCopy:Array = myDisplayObject.filters;
myDisplayObject.addEventListener(MouseEvent.CLICK, addFilters);
Filtro smussatura
La classe BevelFilter consente di aggiungere un effetto di smussatura tridimensionale
all’oggetto filtrato. Questo filtro fa apparire gli spigoli e i bordi vivi dell’oggetto come se
fossero stati cesellati, o smussati.
Le proprietà della classe BevelFilter consentono di personalizzare l’aspetto della smussatura.
È possibile impostare i colori di evidenziazione e d’ombra, le sfocature dei bordi della
smussatura, gli angoli della smussatura e la posizione del bordo della smussatura; è persino
possibile creare un effetto di foratura.
Nell’esempio seguente viene caricata un’immagine esterna a cui viene applicato un filtro di
smussatura.
import flash.display.*;
import flash.filters.BevelFilter;
import flash.filters.BitmapFilterQuality;
import flash.filters.BitmapFilterType;
import flash.net.URLRequest;
bevel.distance = 5;
bevel.angle = 45;
bevel.highlightColor = 0xFFFF00;
bevel.highlightAlpha = 0.8;
bevel.shadowColor = 0x666666;
bevel.shadowAlpha = 0.8;
bevel.blurX = 5;
bevel.blurY = 5;
bevel.strength = 5;
bevel.quality = BitmapFilterQuality.HIGH;
bevel.type = BitmapFilterType.INNER;
bevel.knockout = false;
Filtro sfocatura
La classe BlurFilter sfuma, o sfoca, un oggetto di visualizzazione e il relativo contenuto.
Gli effetti di sfocatura sono utili per dare l’impressione che un oggetto non sia a fuoco o per
simulare un rapido movimento. Impostando la proprietà quality del filtro sfocatura su un
valore basso, è possibile simulare l’effetto di un obiettivo leggermente sfocato. Impostandola
su un valore elevato si ottiene un effetto di sfocatura fluida simile alla sfocatura gaussiana.
L’esempio seguente crea un oggetto circle mediante il metodo drawCircle() della classe
Graphics e a esso applica un filtro sfocatura:
import flash.display.Sprite;
import flash.filters.BitmapFilterQuality;
import flash.filters.BlurFilter;
// Disegna un cerchio.
var redDotCutout:Sprite = new Sprite();
redDotCutout.graphics.lineStyle();
redDotCutout.graphics.beginFill(0xFF0000);
redDotCutout.graphics.drawCircle(145, 90, 25);
redDotCutout.graphics.endFill();
boxShadow.filters = [shadow];
crossGraphic.filters = [glow];
// Disegna un rettangolo.
var box:Shape = new Shape();
box.graphics.lineStyle();
box.graphics.beginFill(0xFEFE78);
box.graphics.drawRect(100, 50, 90, 200);
box.graphics.endFill();
gradientBevel.distance = 8;
gradientBevel.angle = 225; // l’opposto di 45 gradi
gradientBevel.colors = [0xFFFFCC, 0xFEFE78, 0x8F8E01];
gradientBevel.alphas = [1, 0, 1];
gradientBevel.ratios = [0, 128, 255];
gradientBevel.blurX = 8;
gradientBevel.blurY = 8;
gradientBevel.quality = BitmapFilterQuality.HIGH;
box.filters = [gradientBevel];
// Disegna la forma.
shape.graphics.beginFill(0xFF0000, 100);
shape.graphics.moveTo(0, 0);
shape.graphics.lineTo(100, 0);
shape.graphics.lineTo(100, 100);
shape.graphics.lineTo(0, 100);
shape.graphics.lineTo(0, 0);
shape.graphics.endFill();
function onMouseMove(event:MouseEvent):void
{
gradientGlow.blurX = (stage.mouseX / stage.stageWidth) * 255;
gradientGlow.blurY = (stage.mouseY / stage.stageHeight) * 255;
shape.filters = [gradientGlow];
}
stage.addEventListener(MouseEvent.CLICK, onClick);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
var count:Number = 1;
var distance:Number = 8;
var angleInDegrees:Number = 225; // l’opposto di 45 gradi
var colors:Array = [0xFFFFCC, 0xFEFE78, 0x8F8E01];
var alphas:Array = [1, 0, 1];
var ratios:Array = [0, 128, 255];
var blurX:Number = 8;
var blurY:Number = 8;
var strength:Number = 1;
var quality:Number = BitmapFilterQuality.HIGH;
var type:String = BitmapFilterType.INNER;
var knockout:Boolean = false;
switch (count)
{
case 1:
stopLight.filters = [innerShadow];
cautionLight.filters = [yellowGlow];
goLight.filters = [innerShadow];
break;
case 2:
stopLight.filters = [redGlow];
cautionLight.filters = [innerShadow];
goLight.filters = [innerShadow];
break;
case 3:
stopLight.filters = [innerShadow];
cautionLight.filters = [innerShadow];
goLight.filters = [greenGlow];
break;
}
count++;
}
Filtro convoluzione
La classe ConvolutionFilter può essere utilizzata per applicare una vasta gamma di
trasformazioni dell’immagine agli oggetti BitmapData o di visualizzazione, quali le sfocature,
il rilevamento dei bordi, l’aumento della nitidezza, i rilievi e le smussature.
Da un punto di vista concettuale, il filtro convoluzione scorre uno per uno i pixel
nell’immagine di origine e determina il colore finale di ogni pixel mediante il valore del pixel e
di quelli che lo circondano. Una matrice, specificata come array di valori numerici, indica
quanto il valore di ogni pixel vicino influisce sul valore risultante finale.
Si prenda in considerazione il tipo di matrice utilizzato più frequentemente, e cioè una
matrice tre per tre. La matrice include nove valori:
N N N
N P N
N N N
Quando Flash Player applica il filtro convoluzione a un determinato pixel, considera il valore
di colore del pixel stesso (“P” nell’esempio), oltre che i valori dei pixel che lo circondano
(“N” nell’esempio). Tuttavia, impostando i valori nella matrice, si specifica il livello di priorità
di determinati pixel per quanto riguarda l’incidenza sull’immagine risultante.
Ad esempio, la matrice seguente, applicata mediante un filtro convoluzione, lascia l’immagine
esattamente com’è:
0 0 0
0 1 0
0 0 0
Si noti che in questo caso il pixel stesso non ha alcun effetto sul valore finale del pixel
visualizzato in tale posizione dell’immagine finale: solo il valore del pixel sulla destra viene
utilizzato per determinare il valore risultante del pixel.
In ActionScript, si crea la matrice come combinazione di un’istanza Array contenente i valori
e due proprietà che specificano il numero di righe e colonne nella matrice. L’esempio seguente
carica un’immagine e, quando il caricamento è completato, applica un filtro convoluzione
all’immagine mediante la matrice dell’esempio precedente:
// Carica un’immagine sullo stage.
var loader:Loader = new Loader();
var url:URLRequest = new URLRequest("http://www.helpexamples.com/flash/
images/image1.jpg");
loader.load(url);
this.addChild(loader);
function applyFilter(event:MouseEvent):void
{
// Crea la matrice per la convoluzione.
var matrix:Array = [ 0, 0, 0,
0, 0, 1,
0, 0, 0 ];
loader.filters = [convolution];
}
loader.addEventListener(MouseEvent.CLICK, applyFilter);
Si noti che per la maggior parte di questi effetti il divisore è 1. Infatti, i valori di matrice
negativi aggiunti ai valori di matrice positivi producono il risultato 1 (oppure 0 nel caso del
rilevamento dei bordi, ma il valore della proprietà divisor non può essere 0).
var mapImage:BitmapData;
var displacementMap:DisplacementMapFilter;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, setupStage);
Per un esempio più complesso, il codice seguente utilizza un filtro mappa di spostamento per
creare un effetto lente di ingrandimento su un’immagine:
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BitmapDataChannel;
import flash.display.GradientType;
import flash.display.Loader;
import flash.display.Shape;
import flash.events.MouseEvent;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.net.URLRequest;
// Questa funzione viene chiamata ogni volta che il mouse viene spostato.
// Se il mouse è sopra l’immagine caricata, applica il filtro.
function moveMagnifier(event:MouseEvent):void
{
if (loader.hitTestPoint(loader.mouseX, loader.mouseY))
{
magnify();
}
}
loader.addEventListener(MouseEvent.MOUSE_MOVE, moveMagnifier);
Il codice genera innanzi tutto due cerchi con gradiente, che vengono combinati per formare
l’immagine della mappa di spostamento. Il cerchio rosso crea lo spostamento dell’asse x
(xyFilter.componentX = BitmapDataChannel.RED), mentre quello blu crea lo
spostamento dell’asse y (xyFilter.componentY = BitmapDataChannel.BLUE). Per
semplificare l’aspetto dell’immagine della mappa di spostamento, il codice aggiunge sia i
cerchi originali che i cerchi combinati che fungono da immagine della mappa nella parte
inferiore dello schermo.
Sommario
Elementi fondamentali dei clip filmato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 529
Controllo della riproduzione di clip filmato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .532
Creazione di oggetti MovieClip mediante ActionScript . . . . . . . . . . . . . . . . . . . . . . .536
Caricamento di un file SWF esterno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 540
Esempio: RuntimeAssetsExplorer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542
529
Quando un’istanza di un clip filmato viene posizionata sullo stage, il clip filmato avanza
automaticamente lungo la propria linea temporale (se è composto da più di un fotogramma),
a meno che non se ne modifichi la riproduzione mediante ActionScript. È proprio questa
linea temporale che contraddistingue la classe MovieClip, perché consente di creare
animazioni mediante le interpolazioni di movimento e di forma con lo strumento di creazione
di Flash. Al contrario, con un oggetto di visualizzazione che è un’istanza della classe Sprite, è
possibile creare animazioni solo modificando a livello di codice i valori dell’oggetto.
Nelle precedenti versioni di ActionScript, la classe MovieClip costituiva la classe di base di
tutte le istanze sullo stage. In ActionScript 3.0, un clip filmato è solo uno dei numerosi oggetti
di visualizzazione che possono comparire sullo schermo. Se una linea temporale non è
necessaria per la funzione di un oggetto di visualizzazione, l’utilizzo della classe Shape o della
classe Sprite al posto della classe MovieClip può migliorare le prestazioni del rendering. Per
ulteriori informazioni su come scegliere l’oggetto di visualizzazione più adatto a
un’operazione, vedere “Scelta di una sottoclasse DisplayObject” a pagina 421.
Mentre alcuni metodi e proprietà della classe MovieClip di ActionScript 2.0 rimangono
uguali, altri sono cambiati. Tutte le proprietà precedute da un carattere di sottolineatura sono
state ridenominate. Ad esempio, alle proprietà _width e _height si accede ora come width e
height, mentre a _xscale e _yscale si accede come scaleX e scaleY. Per un elenco
completo delle proprietà e dei metodi della classe MovieClip, consultare la Guida di
riferimento al linguaggio e ai componenti di ActionScript 3.0.
la bicicletta non si muove (cioè, la sua animazione non viene riprodotta). Il movimento della
bicicletta può essere avviato mediante altre interazioni dell’utente. Ad esempio, se è presente
un pulsante di nome startButton, il codice seguente su un fotogramma chiave della linea
temporale fa in modo che il clic sul pulsante avvii la riproduzione dell’animazione:
// Questa funzione viene chiamata quando si fa clic sul pulsante. Attiva la
// riproduzione dell’animazione della bicicletta.
function playAnimation(event:MouseEvent):void
{
bicycle.play();
}
// Registra la funzione come listener con il pulsante.
startButton.addEventListener(MouseEvent.CLICK, playAnimation);
Nella riproduzione normale, se un clip filmato contiene più di un solo fotogramma, viene
ripetuto ciclicamente in modo indefinito durante la riproduzione; ovvero, ritorna al
fotogramma 1 se avanza oltre il proprio fotogramma finale. Quando si utilizza prevFrame() o
nextFrame(), questo comportamento non si verifica automaticamente (se si chiama
prevFrame() quando l’indicatore di riproduzione si trova sul fotogramma 1, l’indicatore di
riproduzione non viene spostato all’ultimo fotogramma). La condizione if nell’esempio
precedente verifica se l’indicatore di riproduzione si è spostato all’indietro fino al primo
fotogramma e imposta l’indicatore di riproduzione sul fotogramma finale, creando un ciclo
continuo del clip filmato che viene eseguito all’indietro.
File Descrizione
RuntimeAssetsExample.mxml L’interfaccia utente dell’applicazione per Flex
oppure (MXML) o Flash (FLA).
RuntimeAssetsExample.fla
}
public function getAssets():Array {
return [
"com.example.programmingas3.runtimeassetexplorer.AnimatingBox",
"com.example.programmingas3.runtimeassetexplorer.AnimatingStar" ];
}
}
}
Nel caso sia necessario creare una seconda libreria di runtime, è possibile creare un altro file
FLA in base a un’altra classe (ad esempio, AnimationAssets) che fornisce la propria
implementazione getAssets().
In questo metodo, la variabile rl rappresenta il file SWF caricato. Il codice chiama il metodo
getAssets() del file SWF caricato e ottiene l’elenco delle risorse disponibili, che utilizza per
compilare un componente ComboBox con un elenco di risorse disponibili chiamando il
metodo populateDropDown(). A propria volta, questo metodo memorizza il percorso di
classe completo di ogni risorsa. Se si fa clic sul pulsante Aggiungi dell’interfaccia utente, viene
attivato il metodo addAsset():
private function addAsset():void
{
var className:String = assetNameCbo.selectedItem.data;
var AssetClass:Class = getDefinitionByName(className) as Class;
var mc:MovieClip = new AssetClass();
...
}
che ottiene il percorso di classe della risorsa correntemente selezionata nel componente
ComboBox (assetNameCbo.selectedItem.data) e utilizza la funzione
getDefinitionByName() (del pacchetto flash.utils) per ottenere un riferimento reale alla
classe della risorsa per poter creare una nuova istanza di tale risorsa.
Sommario
Nozioni fondamentali sulle operazioni con il testo . . . . . . . . . . . . . . . . . . . . . . . . . . .548
Visualizzazione del testo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 551
Selezione ed elaborazione del testo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 555
Rilevamento dell’input di testo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .557
Limitazione dell’input di testo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .558
Formattazione del testo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559
Rendering avanzato del testo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .563
Operazioni con il testo statico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .566
Esempio: Formattazione del testo in stile quotidiano. . . . . . . . . . . . . . . . . . . . . . . . .568
547
Nozioni fondamentali sulle operazioni
con il testo
Tipi di testo
Il tipo di testo all’interno di un campo di testo è caratterizzato dalla propria origine:
■ Testo dinamico
Il testo dinamico comprende i contenuti che vengono caricati da un’origine esterna, quale
un file di testo, un file XML o un servizio Web remoto. Per ulteriori informazioni, vedere
“Tipi di testo” a pagina 551.
■ Testo di input
Il testo di input è rappresentato dal testo immesso dall’utente o dal testo dinamico
modificabile dall’utente. È possibile impostare un foglio di stile per la formattazione del
testo di input oppure utilizzare la classe flash.text.TextFormat per assegnare delle proprietà
al campo di testo per il contenuto di input. Per ulteriori informazioni, vedere
“Rilevamento dell’input di testo” a pagina 557.
■ Testo statico
Il testo statico viene creato solo mediante lo strumento di creazione di Flash. Non è
possibile creare un’istanza di testo statico mediante ActionScript: Tuttavia, è possibile
utilizzare le classi ActionScript come StaticText e TextSnapshot per manipolare un’istanza
di testo statico esistente. Per ulteriori informazioni, vedere “Operazioni con il testo
statico” a pagina 566.
Inoltre, alla proprietà text è possibile assegnare un valore tratto da una variabile definita nello
script, come indicato nell’esempio seguente:
package
{
import flash.display.Sprite;
import flash.text.*;
In alternativa, alla proprietà text è possibile assegnare un valore tratto da una variabile
remota. Per caricare i valori di testo da origini remote sono disponibili tre opzioni:
■ Le classi flash.net.URLLoader e flash.net.URLRequest caricano le variabili per il testo da
una posizione locale o remota.
■ L’attributo FlashVars è incorporato nella pagina HTML che include il file SWF e può
contenere dei valori delle variabili di testo.
■ La classe flash.net.SharedObject gestisce la memorizzazione persistente dei valori. Per
ulteriori informazioni, vedere “Memorizzazione di dati locali” a pagina 711.
Flash Player supporta un sottoinsieme di tag ed entità HTML per la proprietà htmlText.
La descrizione della proprietà flash.text.TextField.htmlText nella Guida di riferimento
al linguaggio e ai componenti di ActionScript 3.0 fornisce informazioni dettagliate sui tag e le
entità HTML supportate.
Una volta designato il contenuto mediante la proprietà htmlText, è possibile utilizzare i fogli
di stile o il tag textformat per gestire la formattazione del contenuto. Per ulteriori
informazioni, vedere “Formattazione del testo” a pagina 559.
addChild(myTextBox);
myTextBox.htmlText = myText;
}
}
}
myTextBox.defaultTextFormat = format;
addChild(myTextBox);
myTextBox.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownScroll);
}
function selectText(event:MouseEvent):void
{
myTextField.setSelection(49, 65);
}
In modo analogo, se si desidera che il testo all’interno di un campo di testo venga selezionato
quando il testo viene inizialmente visualizzato, creare una funzione di gestore di eventi che
viene chiamata non appena il campo di testo viene aggiunto all’elenco di visualizzazione.
function selectText(event:MouseEvent):void
{
trace("First letter index position: " + myTextField.selectionBeginIndex);
trace("Last letter index position: " + myTextField.selectionEndIndex);
}
}
}
La proprietà restrict è un po’ più complessa, dal momento che richiede di specificare quali
caratteri l’utente è autorizzato a digitare in un campo di testo di input. È possibile consentire
specificamente lettere, numeri o intervalli di lettere, numeri e caratteri. Il codice seguente
consente all’utente di immettere solo lettere maiuscole (e non numeri o caratteri speciali) nel
campo di testo:
myTextBox.restrict = “A-Z”;
tf.setTextFormat(format1);
var startRange:uint = 6;
tf.setTextFormat(format2, startRange);
addChild(tf);
addChild(tf);
Una volta creato l’oggetto StyleSheet, il codice di esempio crea un oggetto semplice che
contiene un set di proprietà di dichiarazioni di stile. Quindi, chiama il metodo
StyleSheet.setStyle(), che aggiunge il nuovo stile al foglio di stile di nome “.darkred”.
Quindi, applica la formattazione del foglio di stile assegnando l’oggetto StyleSheet alla
proprietà styleSheet dell’oggetto TextField.
Affinché gli stili CSS abbiano effetto, i fogli di stile devono essere applicati all’oggetto
TextField prima di impostare la proprietà htmlText.
h1 {
font-family: Arial, Helvetica, _sans;
font-size: 20;
font-weight: bold;
}
.bluetext {
color: #0000CC;
}
Quando i dati CSS vengono caricati, il metodo onCSSFileLoaded() viene eseguito e chiama
il metodo StyleSheet.parseCSS() per trasferire le dichiarazioni di stile all’oggetto
StyleSheet.
function changeText(event:MouseEvent):void
{
myTextField.setTextFormat(myformat, 49, 65);
}
L a p r o p r ie t à flash.text.TextField.antiAliasType d ev e co n t e n er e il v a l o r e
AntiAliasType.ADVANCED ( ch e è q u el lo p r e de fi n i t o ) p e r c o n se n t i r e d i i m p o st a r e la
p r e ci s i o n e , l o s p es s o r e o la p r o p r i et à gridFitType o p e r u t il i z z a r e i l m et o d o
TextRenderer.setAdvancedAntiAliasingTable().
function clickHandler(event:Event):void
{
var myAntiAliasSettings = new CSMSettings(48, 0.8, -0.8);
var myAliasTable:Array = new Array(myAntiAliasSettings);
TextRenderer.setAdvancedAntiAliasingTable("myFont", FontStyle.ITALIC,
TextColorType.DARK_COLOR, myAliasTable);
}
Una volta creato un riferimento a un campo di testo statico, è possibile utilizzare le proprietà
di questo campo in ActionScript 3.0. Il codice che segue è associato a un fotogramma nella
linea temporale e assume una variabile chiamata myFieldLabel assegnata a un riferimento di
testo statico. Nell’esempio, un campo di testo dinamico di nome myField viene posizionato
in relazione ai valori x e y di myFieldLabel e visualizza di nuovo il valore di myFieldLabel.
var myField:TextField = new TextField();
addChild(myField);
myField.x = myFieldLabel.x;
myField.y = myFieldLabel.y + 20;
myField.autoSize = TextFieldAutoSize.LEFT;
myField.text = "and " + myFieldLabel.text
La classe TextSnapshot è utile per ottenere il testo dai campi di testo statici di un file SWF
caricato, nel caso si desideri utilizzare il testo come valore in un’altra parte dell’applicazione.
File Descrizione
NewsLayout.mxml L’interfaccia utente dell’applicazione per Flex
oppure (MXML) o Flash (FLA).
NewsLayout.fla
h1 {
font-family: Verdana, Arial, Helvetica, _sans;
font-size: 20;
font-weight: bold;
color: #000099;
text-align: left;
}
h2 {
font-family: Verdana, Arial, Helvetica, _sans;
font-size: 16;
font-weight: normal;
text-align: left;
}
if (style.hasOwnProperty("letterSpacing"))
{
format.letterSpacing = style.letterSpacing;
}
}
return format;
}
I nomi di proprietà e il significato dei valori di proprietà nelle dichiarazioni di stile CSS sono
diversi rispetto agli oggetti TextFormat. Il metodo getTextStyle() converte i valori delle
proprietà CSS nei valori previsti dall’oggetto TextFormat.
Ogni campo viene semplicemente posizionato al di sotto del campo precedente impostandone
la proprietà y sul valore della proprietà y del campo precedente più l’altezza del campo
precedente. Questo calcolo di posizionamento dinamico è necessario poiché gli oggetti
HeadlineTextField e gli oggetti MultiColumnTextField possono modificare la propria altezza
per adattarsi ai contenuti.
if (targetWidth == -1)
{
targetWidth = this.width;
}
if (pointSize < 6)
{
// La dimensione in punti è troppo piccola
return pointSize;
}
this.changeSize(pointSize + 1);
this.changeSize(pointSize);
this.fieldArray.push(field);
this.addChild(field);
}
Ogni oggetto TextField viene aggiunto all’array e all’elenco di visualizzazione con il metodo
addChild().
Ogni qual volta la proprietà text o styleSheet dell’oggetto StoryLayout cambia, chiama il
metodo layoutColumns() per rivisualizzare il testo. Il metodo layoutColumns() chiama il
metodo getOptimalHeight(), mostrato di seguito, per determinare l’altezza in pixel
necessaria per adattare tutto il testo all’interno della larghezza di layout data.
public function getOptimalHeight(str:String):int
{
if (fieldArray.length == 0 || str == "" || str == null)
{
return this.preferredHeight;
}
else
{
var colWidth:int = Math.floor( (this.preferredWidth -
((this.numColumns - 1) * gutter)) / this.numColumns);
if (this.fitToText)
{
this.preferredHeight = this.getOptimalHeight(this._text);
}
remainder = "";
fieldText = "";
Sommario
Nozioni fondamentali sulle operazioni con le bitmap . . . . . . . . . . . . . . . . . . . . . . . . . 577
Le classi Bitmap e BitmapData. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581
Manipolazione dei pixel. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .583
Copia dei dati bitmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587
Creazione di texture mediante le funzioni di disturbo . . . . . . . . . . . . . . . . . . . . . . . . .588
Scorrimento delle bitmap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
Esempio: Animazione di sprite mediante una bitmap fuori schermo . . . . . . . . . . 592
577
Le immagini bitmap sono definite dalla larghezza e dall’altezza dell’immagine, misurate in
pixel, e dal numero di bit contenuti in ogni pixel, che rappresenta il numero di colori che un
pixel è in grado di contenere. Nel caso di un’immagine bitmap che utilizza il modello di colore
RGB, i pixel sono costituiti da tre byte: rosso, verde e blu. Ognuno di questi byte contiene un
valore compreso tra 0 e 255. Quando i byte vengono combinati all’interno del pixel,
producono un colore simile a quello ottenuto da un pittore quando miscela i colori.
Ad esempio, un pixel che contiene valori in byte di rosso-255, verde-102 e blu-0 produce un
arancione brillante.
La qualità di un’immagine bitmap viene determinata combinando la risoluzione
dell’immagine con il relativo valore in bit della profondità di colore. La risoluzione fa
riferimento al numero di pixel contenuti all’interno di un’immagine. Maggiore è il numero di
pixel, più elevata è la risoluzione e più accurata appare l’immagine. La profondità di colore fa
riferimento alla quantità di informazioni che un pixel è in grado di contenere. Ad esempio,
un’immagine che ha un valore di profondità di colore di 16 bit per pixel non può
rappresentare lo stesso numero di colori di un’immagine che ha una profondità di colore di
48 bit. Di conseguenza, l’immagine a 48 bit ha dei livelli di ombreggiatura più attenuati
rispetto alla sua controparte a 16 bit.
Dal momento che gli elementi grafici bitmap dipendono dalla risoluzione, quando vengono
modificati in scala non producono risultati ottimali. Questa situazione è particolarmente
evidente quando le immagini bitmap vengono ingrandite in scala. L’ingrandimento in scala di
solito produce una perdita di dettaglio e di qualità.
GIF
Il formato Graphics Interchange Format (GIF) è stato originariamente sviluppato da
CompuServe nel 1987 come mezzo per trasmettere le immagini a 256 colori (colore a 8 bit).
Il formato fornisce dimensioni di file ridotte ed è ideale per le immagini basate sul Web.
A causa della tavolozza colori limitata, le immagini GIF di solito non sono adattate per le
fotografie, che generalmente richiedono livelli elevati di ombreggiatura e gradienti di colore.
Le immagini GIF consentono la trasparenza a livello di singolo bit, che permette di mappare i
colori come trasparenti. Ciò comporta che il colore di sfondo di una pagina Web è visibile
attraverso l’immagine nei punti in cui la trasparenza è stata mappata.
PNG
Il formato Portable Network Graphics (PNG) è stato creato come alternativa open-source al
formato GIF brevettato. I file PNG supportano una profondità di colore fino a 64 bit,
consentendo la riproduzione fino a 16 milioni di colori. Dal momento che il PNG è un
formato relativamente recente, non è supportato da alcuni dei browser più datati. A differenza
dei JPG, i file PNG utilizzano una compressione senza perdita: in altre parole, quando
l’immagine viene salvata non va perso alcun dato di immagine. I file PNG supportano anche
la trasparenza alfa, che consente fino a 256 livelli di trasparenza.
Spesso, quando le immagini bitmap vengono modificate in scala, diventano sfocate e distorte.
Per ridurre questa distorsione, utilizzare la proprietà smoothing della classe BitmapData.
Questa proprietà booleana, se impostata su true, attenua (mediante antialiasing) i pixel
all’interno dell’immagine quando quest’ultima viene modificata in scala. In questo modo,
l’aspetto dell’immagine risulta più chiaro e naturale.
Per effettuare il rendering di un oggetto BitmapData appena creato sullo schermo, assegnarlo
o racchiuderlo in un’istanza Bitmap. A tale scopo, è possibile passare l’oggetto BitmapData
come parametro della funzione di costruzione dell’oggetto Bitmap oppure assegnarlo alla
proprietà bitmapData di un’istanza Bitmap esistente. È anche necessario aggiungere l’istanza
Bitmap all’elenco di visualizzazione chiamando i metodi addChild() o addChildAt() del
contenitore dell’oggetto di visualizzazione che deve contenere l’istanza. Per ulteriori
informazioni sulle operazioni con l’elenco di visualizzazione, vedere “Aggiunta di oggetti di
visualizzazione all’elenco di visualizzazione” a pagina 408.
L’esempio seguente crea un oggetto BitmapData con un riempimento rosso e lo visualizza in
un’istanza Bitmap:
var myBitmapDataObject:BitmapData = new BitmapData(150, 150, false,
0xFF0000);
var myImage:Bitmap = new Bitmap(myBitmapDataObject);
addChild(myImage);
bytes.position = 0;
bitmapDataObject2.setPixels(rect, bytes);
Come suggerisce il nome stesso, il metodo clone() consente di clonare, o campionare, i dati
bitmap da un oggetto BitmapData a un altro. Quando viene chiamato, il metodo restituisce
un nuovo oggetto BitmapData che è un clone esatto dell’istanza originale da cui è stato
copiato.
L’esempio seguente clona una copia di un quadrato arancione (principale) e posiziona il clone
accanto al quadrato principale originale:
import flash.display.Bitmap;
import flash.display.BitmapData;
Se l’oggetto di origine ha subito delle trasformazioni (colore, matrice e così via) dopo che è
stato originariamente caricato, queste trasformazioni non vengono copiate nel nuovo oggetto.
Se si desidera copiare le trasformazioni nella nuova bitmap, è necessario copiare il valore della
proprietà transform dall’oggetto originale alla proprietà transform dell’oggetto Bitmap che
utilizza il nuovo oggetto BitmapData.
addEventListener(Event.ENTER_FRAME, scrollBitmap);
function scrollBitmap(event:Event):void
{
myBitmapDataObject.scroll(1, 1);
}
Sommario
Elementi fondamentali del video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
Nozioni fondamentali sul formato Flash Video (FLV) . . . . . . . . . . . . . . . . . . . . . . . .597
Nozioni fondamentali sulla classe Video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .598
Caricamento di file video. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 599
Controllo della riproduzione video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 600
Streaming di file video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 602
Nozioni fondamentali sui cue point. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 603
Scrittura di metodi di callback per onCuePoint e onMetaData . . . . . . . . . . . . . . . 604
Uso dei cue point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 610
Uso di metadati video . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .611
Rilevamento dell’input da videocamera. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 615
Argomenti avanzati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .623
Esempio: Video Jukebox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .625
593
Elementi fondamentali del video
Per caricare file FLV da un server Web, potrebbe essere necessario registrare
l’estensione e il tipo MIME del file con il server Web. A questo proposito, consultare
la documentazione del server Web. Il tipo MIME per i file FLV è video/x-flv. Per
ulteriori informazioni, vedere “Informazioni sulla configurazione di file FLV per
l’hosting su un server” a pagina 624.
Le istanze di un oggetto Video sullo stage sono istanze della classe Video.
Anche se fa parte del pacchetto flash.media, la classe Video eredita dalla classe
flash.display.DisplayObject e pertanto tutte le funzionalità relative agli oggetti di
visualizzazione (ad esempio, le trasformazioni mediante matrice e i filtri) valgono anche per le
istanze Video.
Per ulteriori informazioni, vedere “Manipolazione di oggetti di visualizzazione” a pagina 422,
“Operazioni con le funzioni geometriche” a pagina 463 e “Filtraggio degli oggetti di
visualizzazione” a pagina 501.
2. La seconda operazione consiste nel creare un oggetto NetStream che riceve un oggetto
NetConnection come parametro e nello specificare quale file FLV si desidera caricare.
Lo snippet di codice seguente collega un oggetto NetStream all’istanza NetConnection
specificata e carica un file FLV di nome video.flv nella stessa directory del file SWF:
var ns:NetStream = new NetStream(nc);
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
ns.play("video.flv");
function asyncErrorHandler(event:AsyncErrorEvent):void
{
// Ignora l’errore
}
3. La terza operazione consiste nel creare un nuovo oggetto Video e associare l’oggetto
NetStream creato in precedenza mediante il metodo attachNetStream() della classe
Video. Quindi è possibile aggiungere l’oggetto Video all’elenco di visualizzazione
utilizzando il metodo addChild(), come mostra lo snippet di codice seguente:
var vid:Video = new Video();
vid.attachNetStream(ns);
addChild(vid);
Una volta immesso il codice precedente, Flash Player tenta di caricare il file video video.flv
nella stessa directory del file SWF.
S U G GE R I M E N T O
Per caricare file FLV da un server Web, potrebbe essere necessario registrare
l’estensione e il tipo MIME del file con il server Web. A questo proposito, consultare la
documentazione del server Web. Il tipo MIME per i file FLV è video/x-flv. Per ulteriori
informazioni, vedere “Informazioni sulla configurazione di file FLV per l’hosting su un
server” a pagina 624.
Non è presente alcun metodo stop(). Per poter interrompere uno streaming, è necessario mettere in
pausa la riproduzione e cercare l’inizio del flusso video.
NO TA
Il metodo play() non riprende la riproduzione; viene utilizzato per caricare i file video.
L’esempio seguente mostra come controllare un video mediante diversi pulsanti. Per eseguire
l’esempio seguente, creare un nuovo documento e aggiungere quattro istanze di pulsante
all’area di lavoro (pauseBtn, playBtn, stopBtn e togglePauseBtn):
var nc:NetConnection = new NetConnection();
nc.connect(null);
pauseBtn.addEventListener(MouseEvent.CLICK, pauseHandler);
playBtn.addEventListener(MouseEvent.CLICK, playHandler);
stopBtn.addEventListener(MouseEvent.CLICK, stopHandler);
togglePauseBtn.addEventListener(MouseEvent.CLICK, togglePauseHandler);
function pauseHandler(event:MouseEvent):void
{
ns.pause();
}
Se si fa clic sull’istanza del pulsante pauseBtn mentre il video è in corso di riproduzione, il file
video viene messo in pausa. Se il video è già in pausa, il clic su questo pulsante non ha alcun
effetto. Se si fa clic sull’istanza del pulsante playBtn, viene ripresa la riproduzione del video se
quest’ultima era stata precedentemente messa in pausa; in caso contrario, il pulsante non ha
alcun effetto se il video era già in fase di riproduzione.
Il codice precedente carica un file FLV locale di nome video.flv e intercetta l’evento
asyncError (AsyncErrorEvent.ASYNC_ERROR) da inviare. L’evento viene inviato quando
viene generata un’eccezione da un codice asincrono nativo. In questo caso, viene inviato
quando un file FLV contiene dei metadati o delle informazioni relative ai cue point e non
sono stati definiti i listener appropriati. Il codice precedente gestisce l’evento asyncError e
ignora l’errore se non si è interessati ai metadati o alle informazioni sui cue point presenti nel
file video. Se fosse presente un file FLV contenente dei metadati e diversi cue point,
verrebbero tracciate le informazioni seguenti:
Errore #2095: flash.net.NetStream non è riuscito a richiamare il callback
onMetaData.
Errore #2095: flash.net.NetStream non è riuscito a richiamare il callback
onCuePoint.
Errore #2095: flash.net.NetStream non è riuscito a richiamare il callback
onCuePoint.
Errore #2095: flash.net.NetStream non è riuscito a richiamare il callback
onCuePoint.
Anche in assenza di gestori per i gestori di callback onMetaData e onCuePoint non vengono
generati errori, poiché la classe DynamicCustomNetStream è dinamica. Se si desidera definire
i metodi per i gestori di callback onMetaData e onCuePoint, è possibile utilizzare il codice
seguente:
var ns:DynamicCustomNetStream = new DynamicCustomNetStream();
ns.onMetaData = metaDataHandler;
ns.onCuePoint = cuePointHandler;
ns.play("http://www.helpexamples.com/flash/video/cuepoints.flv");
function metaDataHandler(infoObject:Object):void
{
trace("metadata");
}
function cuePointHandler(infoObject:Object):void
{
trace("cue point");
}
Se viene chiamato il gestore di callback onMetaData o onCuePoint e non esiste alcun metodo
per gestire il callback, non viene generato alcun errore. Per gestire questi gestori di callback,
creare un metodo onMetaData() e onCuePoint() nel codice, come mostrato nello snippet
seguente:
function onMetaData(infoObject:Object):void
{
trace("metadata");
}
function onCuePoint(infoObject:Object):void
{
trace("cue point");
}
Questo codice utilizza una delle numerose tecniche disponibili per impostare l’oggetto su cui è
stato richiamato il metodo di callback. Per informazioni sulle altre tecniche che è possibile
utilizzare, vedere Scrittura di metodi di callback per onCuePoint e onMetaData.
function onMetaData(infoObject:Object):void
{
var key:String;
for (key in infoObject)
{
trace(key + ": " + infoObject[key]);
}
}
Nel codice precedente, le informazioni sui cue point non erano visualizzate. Per poter
visualizzare i metadati dei cue point, è possibile utilizzare la funzione seguente che visualizza
in modo ricorsivo gli elementi in un oggetto:
function traceObject(obj:Object, indent:uint = 0):void
{
var indentString:String = "";
var i:uint;
var prop:String;
var val:*;
for (i = 0; i < indent; i++)
{
indentString += "\t";
}
for (prop in obj)
{
val = obj[prop];
if (typeof(val) == "object")
{
trace(indentString + " " + j + ": [Object]");
traceObject(val, indent + 1);
}
else
{
trace(indentString + " " + prop + ": " + val);
}
}
}
Parametro Descrizione
audiocodecid Un numero che indica il codec audio (tecnica code/decode)
utilizzato.
audiodelay Un numero che indica il tempo del file FLV “time 0” del file FLV
originale. Il contenuto video deve essere leggermente ritardato
per sincronizzare correttamente l’audio.
cuePoints Un array di oggetti, uno per ciascun cue point incorporato nel file
FLV. Il valore è undefined se il file FLV non contiene cue point.
Ciascun oggetto ha le seguenti proprietà:
■ type: una stringa che specifica se il cue point è di tipo “navigation” o
“event”.
■ name: una stringa che indica il nome del cue point.
■ time: un numero che specifica il tempo del cue point in secondi e considera
solo i primi tre decimali (millisecondi).
■ parameters: un oggetto opzionale in cui le coppie nome-valore vengono
definite dall’utente durante la creazione dei cue point.
height Un numero che specifica l’altezza del file FLV, espressa in pixel.
Nella tabella seguente sono riportati i valori possibili per il parametro videocodecid:
Nella tabella seguente sono riportati i valori possibili per il parametro audiocodecid:
1 ADPCM
2 mp3
5 Nellymoser 8kHz
mono
6 Nellymoser
La classe Camera non contiene un metodo di costruzione. Per creare una nuova istanza
Camera si utilizza il metodo statico Camera.getCamera().
Si noti che se per un utente non è installata una videocamera, Flash Player non
visualizza nulla.
Nella realtà, è necessario eseguire delle operazioni supplementari per l’applicazione. Per
ulteriori informazioni, vedere Verifica dell’installazione delle videocamere e Rilevamento delle
autorizzazioni per l’accesso alla videocamera.
Dal momento che la classe Camera non estende la classe DisplayObject, non può essere
aggiunta direttamente all’elenco di visualizzazione mediante il metodo addChild(). Per
visualizzare il video acquisito dalla videocamera, creare un nuovo oggetto Video e chiamare il
metodo attachCamera() sull’istanza Video.
Questo snippet di codice mostra come associare la videocamera (se presente); in caso
contrario, Flash Player non visualizza nulla:
var cam:Camera = Camera.getCamera();
if (cam != null)
{
var vid:Video = new Video();
vid.attachCamera(cam);
addChild(vid);
}
Verificando l’avvenuto invio dell’evento status, è possibile scrivere del codice che gestisce
l’accettazione o il rifiuto da parte dell’utente dell’accesso alla videocamera ed eseguire la
pulizia appropriata del codice. Ad esempio, se l’utente fa clic sul pulsante Nega, è possibile
visualizzare un messaggio che avvisa che è necessario fare clic su Consenti per partecipare a
una chat video oppure è possibile fare in modo che l’oggetto Video nell’elenco di
visualizzazione venga eliminato per liberare risorse di sistema.
if (cam == null)
{
trace("Unable to locate available cameras.");
}
else
{
trace("Found camera: " + cam.name);
cam.addEventListener(StatusEvent.STATUS, statusHandler);
vid = new Video();
vid.attachCamera(cam);
}
function statusHandler(event:StatusEvent):void
{
if (cam.muted)
{
trace("Unable to connect to active camera.");
}
else
{
// Ridimensiona l’oggetto Video per farlo corrispondere alle
// impostazioni della videocamera e
// aggiunge il video all’elenco di visualizzazione.
vid.width = cam.width;
vid.height = cam.height;
addChild(vid);
}
// Rimuove il listener di eventi status.
cam.removeEventListener(StatusEvent.STATUS, statusHandler);
}
if (cam != null)
{
cam.addEventListener(StatusEvent.STATUS, statusHandler);
vid = new Video();
vid.attachCamera(cam);
}
function statusHandler(event:StatusEvent):void
{
if (!cam.muted)
{
vid.width = cam.width;
vid.height = cam.height;
addChild(vid);
t.start();
}
cam.removeEventListener(StatusEvent.STATUS, statusHandler);
}
Ogni 1/10 di secondo (100 millisecondi) l’evento timer dell’oggetto Timer viene inviato e la
funzione timerHandler() aggiorna il campo di testo nell’elenco di visualizzazione.
Argomenti avanzati
Gli argomenti seguenti illustrano alcuni particolari problemi che si verificano quando si lavora
con il video.
7 7, 8
On2 VP6 6 8*
7 8
8 8
* Se il file SWF carica un file FLV, è possibile utilizzare il video On2 VP6 con l’obbligo di
ripubblicare il file SWF per Flash Player 8, sempre che gli utenti, per visualizzare il file
SWF, utilizzino Flash Player 8. Solo Flash Player 8 supporta sia la pubblicazione che la
riproduzione di video On2 VP6.
Il motivo della mancata riproduzione è una limitazione del sistema operativo e non di
Flash Player.
Per riprodurre un file FLV proveniente da un’unità non di sistema in Macintosh, fare
riferimento a esso con un percorso assoluto utilizzando una notazione basata sui due punti (:)
al posto di una notazione basata sulla barra laterale (/). L’elenco seguente mostra le differenze
tra i due tipi di notazione:
■ Notazione basata sulla barra laterale: myDrive/myFolder/myFLV.flv
■ Notazione basata sui due punti: (Mac OS®) myDrive:myFolder:myFLV.flv
È anche possibile creare un file di proiettore per un CD-ROM che si prevede di utilizzare per
la riproduzione in Macintosh. Per informazioni aggiornate sui CD-ROM Mac OS e i file FLV,
vedere www.adobe.com/go/3121b301_it.
File Descrizione
VideoJukebox.as La classe che fornisce la funzionalità principale
dell’applicazione.
Questo codice viene collocato nella funzione di costruzione della classe VideoJukebox in
modo che il file venga caricato prima che venga eseguito qualunque altro codice. Non appena
è terminato il caricamento del file XML, viene chiamato il metodo xmlCompleteHandler()
che analizza il file esterno in un oggetto XML, come mostrato nel codice seguente:
private function xmlCompleteHandler(event:Event):void
{
playlist = XML(event.target.data);
videosXML = playlist.video;
main();
}
L’oggetto playlist XML contiene i dati XML originari del file esterno, mentre videosXML è un
oggetto XMLList che contiene solo i nodi video. Lo snippet di codice seguente contiene un
esempio di un file playlist.xml:
<videos>
<video url="video/caption_video.flv" />
<video url="video/cuepoints.flv" />
<video url="video/water.flv" />
</videos>
ns = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
ns.client = client;
Il metodo netStatusHandler() viene chiamato ogni qual volta lo stato del video viene
modificato; ad esempio quando la riproduzione del video viene avviata o interrotta, quando il
video è in fase di bufferizzazione o se non è possibile trovare uno streaming video. Il codice
seguente elenca l’evento netStatusHandler():
private function netStatusHandler(event:NetStatusEvent):void
{
try
{
switch (event.info.code)
{
case "NetStream.Play.Start":
t.start();
break;
case "NetStream.Play.StreamNotFound":
case "NetStream.Play.Stop":
t.stop();
playNextVideo();
break;
}
}
catch (error:TypeError)
{
// Ignora qualunque errore.
}
}
Sommario
Nozioni fondamentali sulle operazioni con l’audio . . . . . . . . . . . . . . . . . . . . . . . . . . .634
Nozioni fondamentali sull’architettura audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 637
Caricamento di file audio esterni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .639
Operazioni con l’audio incorporato. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .642
Operazioni con l’audio in streaming . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 644
Riproduzione dell’audio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .645
Considerazioni sulla sicurezza durante il caricamento e la riproduzione
dell’audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649
Controllo del volume e della panoramica dell’audio . . . . . . . . . . . . . . . . . . . . . . . . . 650
Operazioni con i metadati audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .653
Accesso ai dati audio originari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .653
Rilevamento dell’input audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .658
Esempio: Podcast Player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .662
633
Nozioni fondamentali sulle operazioni
con l’audio
dove “click.mp3” è il nome del file audio che verrà caricato. Per provare questi esempi, è
necessario disporre di un file mp3 e collocarlo nella stessa cartella del documento Flash. In
seguito, è necessario modificare il codice in modo che utilizzi il nome di questo file mp3 al
posto del nome presente nell’esempio di codice (ad esempio, nel codice sopra occorre
sostituire “click.mp3” con il nome del proprio file mp3).
Ogni risorsa audio che viene caricata e riprodotta richiede una propria istanza della classe
Sound e della classe SoundChannel. L’output proveniente da più istanze SoundChannel viene
quindi combinato dalla classe SoundMixer globale durante la riproduzione.
Le classi Sound, SoundChannel e SoundMixer non vengono utilizzate per i dati audio
ottenuti da un microfono o dallo streaming di un server multimediale come Flash Media
Server.
Evento Descrizione
open (Event.OPEN) Inviato appena prima dell’inizio dell’operazione di
caricamento dell’audio.
id3 (Event.ID3) Inviato quando sono disponibili dati ID3 per un file
audio mp3.
complete (Event.COMPLETE) Inviato quando sono stati caricati tutti i dati della
risorsa audio.
Il codice riportato di seguito illustra come riprodurre un file audio dopo che ne è terminato il
caricamento:
import flash.events.Event;
import flash.media.Sound;
import flash.net.URLRequest;
Come prima cosa, l’esempio di codice crea un nuovo oggetto Sound senza assegnare un valore
iniziale per il relativo parametro URLRequest. Quindi, intercetta l’evento Event.COMPLETE
dall’oggetto Sound, provocando l’esecuzione del metodo onSoundLoaded() quando sono
stati caricati tutti i dati audio. Infine, chiama il metodo Sound.load() con un nuovo valore
di URLRequest per il file audio.
Il metodo onSoundLoaded() viene eseguito quando il caricamento dell’audio è completato.
La proprietà target dell’oggetto Event è un riferimento all’oggetto Sound. Quando si chiama il
metodo play() dell’oggetto Sound, viene avviata la riproduzione dell’audio.
function onLoadProgress(event:ProgressEvent):void
{
var loadedPct:uint =
Math.round(100 * (event.bytesLoaded / event.bytesTotal));
trace("The sound is " + loadedPct + "% loaded.");
}
Questo codice crea innanzi tutto un oggetto Sound, quindi aggiunge dei listener a tale oggetto
per gli eventi ProgressEvent.PROGRESS e Event.COMPLETE. Dopo che il metodo
Sound.load() è stato chiamato e sono stati ricevuti i primi dati dal file audio, si verifica un
evento ProgressEvent.PROGRESS che attiva il metodo onSoundLoadProgress().
La percentuale dei dati audio caricati è uguale al valore della proprietà bytesLoaded
dell’oggetto ProgressEvent divisa per il valore della proprietà bytesTotal. Le stesse proprietà
bytesLoaded e bytesTotal sono disponibili anche nell’oggetto Sound. L’esempio precedente
mostra semplicemente dei messaggi relativi all’avanzamento del caricamento dell’audio, ma è
possibile utilizzare i valori bytesLoaded e bytesTotal per aggiornare i componenti della
barra di avanzamento, ad esempio quelli forniti con la struttura Adobe Flex 2 o nello
strumento di creazione di Flash.
Questo esempio mostra anche come un’applicazione riconosce e risponde a un errore mentre
carica dei file audio. Ad esempio, se non è possibile individuare un file audio con un
determinato nome, l’oggetto Sound invia un evento Event.IO_ERROR. Nel codice precedente,
viene eseguito il metodo onIOError(), che visualizza un breve messaggio di errore quando si
verifica un errore.
Mentre la riproduzione continua, Flash Player cerca di preservare la dimensione del buffer
audio (o di aumentarla). Se i dati audio vengono caricati più rapidamente rispetto alla velocità
di riproduzione, la riproduzione continua senza interruzioni. Tuttavia, se la velocità di
caricamento dei dati rallenta a causa dei limiti della rete, è possibile che l’indicatore di
riproduzione raggiunga la fine del buffer audio. In tal caso, la riproduzione viene sospesa e
ripristinata automaticamente non appena sono stati caricati altri dati audio.
Per determinare se la riproduzione viene sospesa perché Flash Player attende il caricamento dei
dati, utilizzare la proprietà Sound.isBuffering.
In questo esempio, l’audio viene riprodotto da un punto che si trova un secondo dopo l’inizio
del suono, per tre volte in successione.
Tuttavia, questo codice riporta delle percentuali di riproduzione accurate solo se i dati audio
sono stati interamente caricati prima dell’inizio della riproduzione. La proprietà
Sound.length mostra le dimensioni dei dati audio in corso di caricamento, non le
dimensioni finali dell’intero file audio. Per tenere traccia dell’avanzamento della riproduzione
di un file audio in streaming che è ancora in fase di caricamento, l’applicazione deve stimare le
dimensioni finali dell’intero file audio e utilizzare tale valore nei calcoli. È possibile stimare la
lunghezza finale dei dati audio mediante le proprietà bytesLoaded e bytesTotal dell’oggetto
Sound, come indicato di seguito:
var estimatedLength:int =
Math.ceil(snd.length / (snd.bytesLoaded / snd.bytesTotal));
var playbackPercent:uint = 100 * (channel.position / estimatedLength);
var channel:SoundChannel;
channel = snd.play();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
snd.addEventListener(Event.SOUND_COMPLETE, onPlaybackComplete);
function onPlaybackComplete(event:Event)
{
trace("The sound has finished playing.");
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
Una volta avviato il caricamento dei dati audio, questo codice chiama il metodo snd.play()
e memorizza l’oggetto SoundChannel risultante nella variabile channel. Quindi, aggiunge un
listener di eventi all’applicazione principale per l’evento Event.ENTER_FRAME e un altro
listener di eventi all’oggetto SoundChannel per l’evento Event.SOUND_COMPLETE che si
verifica quando la riproduzione è completata.
Ogni volta che l’applicazione raggiunge un nuovo fotogramma della propria animazione,
viene chiamato il metodo onEnterFrame(). Il metodo onEnterFrame() stima la lunghezza
totale del file audio in base alla quantità di dati che sono già stati caricati, quindi calcola e
visualizza la percentuale di riproduzione corrente.
Quando è stato riprodotto l’intero file audio, viene eseguito il metodo
onPlaybackComplete() e viene rimosso il listener di eventi per l’evento Event.ENTER_FRAME
in modo che non tenti di visualizzare gli aggiornamenti sull’avanzamento dopo che la
riproduzione è terminata.
L’evento Event.ENTER_FRAME può essere inviato molte volte al secondo. In determinate
circostanze, non è necessario visualizzare l’avanzamento della riproduzione con tale frequenza.
In tali casi, l’applicazione può impostare il proprio meccanismo di gestione temporale
mediante la classe flash.util.Timer (vedere “Operazioni con data e ora” a pagina 205).
È anche possibile utilizzare un oggetto SoundTransform per impostare i valori del volume e
della panoramica per un oggetto Microphone (vedere “Rilevamento dell’input audio”
a pagina 658) e per gli oggetti Sprite e SimpleButton.
L’esempio seguente alterna la panoramica di un file audio dal canale sinistro a quello destro e
viceversa durante la riproduzione.
import flash.events.Event;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundMixer;
import flash.net.URLRequest;
var panCounter:Number = 0;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(event:Event):void
{
trans.pan = Math.sin(panCounter);
channel.soundTransform = trans; // or SoundMixer.soundTransform = trans;
panCounter += 0.05;
}
function onPlaybackComplete(event:Event):void
{
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
Questo codice inizia caricando un file audio, quindi creando un nuovo oggetto
SoundTransform con il volume impostato su 1 (volume massimo) e la panoramica impostata
su 0 (bilanciamento uniforme tra il canale sinistro e destro). Quindi, chiama il metodo
snd.play(), passando l’oggetto SoundTransform come parametro.
function onID3InfoReceived(event:Event)
{
var id3:ID3Info = event.target.id3;
Questo codice comincia creando un oggetto Sound a cui specifica di intercettare l’evento
Event.ID3. Quando i metadati ID3 del file audio sono stati caricati, viene chiamato il
metodo onID3InfoReceived(). L’elemento di destinazione dell’oggetto Event passato al
metodo onID3InfoReceived() è l’oggetto Sound originale, pertanto il metodo ottiene la
proprietà id3 dell’oggetto Sound e successivamente esegue le iterazioni su tutte le proprie
proprietà indicate per tracciarne i valori.
function onEnterFrame(event:Event):void
{
SoundMixer.computeSpectrum(bytes, false, 0);
g.clear();
g.lineStyle(0, 0x6600CC);
g.beginFill(0x6600CC);
g.moveTo(0, PLOT_HEIGHT);
var n:Number = 0;
// left channel
for (var i:int = 0; i < CHANNEL_LENGTH; i++)
{
n = (bytes.readFloat() * PLOT_HEIGHT);
g.lineTo(i * 2, PLOT_HEIGHT - n);
}
g.lineTo(CHANNEL_LENGTH * 2, PLOT_HEIGHT);
g.endFill();
// right channel
g.lineStyle(0, 0xCC0066);
g.beginFill(0xCC0066, 0.5);
g.moveTo(CHANNEL_LENGTH * 2, PLOT_HEIGHT);
function onPlaybackComplete(event:Event)
{
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
Accesso a un microfono
La classe Microphone non contiene un metodo di costruzione. Per ottenere una nuova istanza
Microphone si utilizza piuttosto il metodo statico Microphone.getMicrophone(), come
mostrato di seguito:
var mic:Microphone = Microphone.getMicrophone();
function onMicStatus(event:StatusEvent):void
{
if (event.code == "Microphone.Unmuted")
{
trace("Microphone access was allowed.");
}
else if (event.code == "Microphone.Muted")
(
trace("Microphone access was denied.");
}
}
In determinati casi, il processo di attivazione del microfono quando viene rilevata della nuova
attività può provocare un lieve ritardo. Tale circostanza può essere evitata mantenendo sempre
attivo il microfono. L’applicazione può chiamare il metodo
Microphone.setSilenceLevel() con il parametro silenceLevel impostato su zero per
specificare a Flash Player di mantenere attivo il microfono e di continuare a raccogliere dati
anche se non viene rilevato alcun suono. Al contrario, se si imposta il parametro
silenceLevel su 100 si impedisce che il microfono venga attivato del tutto.
L’esempio seguente visualizza le informazioni sul microfono e genera un report sugli eventi
activity e sugli eventi status inviati da un oggetto Microphone:
import flash,events.ActivityEvent;
import flash,events.StatusEvent;
import flash.media.Microphone;
mic.addEventListener(ActivityEvent.ACTIVITY, this.onMicActivity);
mic.addEventListener(StatusEvent.STATUS, this.onMicStatus);
function onMicStatus(event:StatusEvent):void
{
trace("status: level=" + event.level + ", code=" + event.code);
}
Quando si esegue il suddetto esempio, parlare o produrre dei suoni nel microfono di sistema e
osservare le istruzioni trace risultanti che vengono visualizzati sulla console o in una finestra
di debug.
File Descrizione
PodcastPlayer.mxml L’interfaccia utente dell’applicazione per Flex
oppure (MXML) o Flash (FLA).
PodcastPlayer.fla
if (autoLoad)
{
load();
}
}
this.s.addEventListener(ProgressEvent.PROGRESS, onLoadProgress);
this.s.addEventListener(Event.OPEN, onLoadOpen);
this.s.addEventListener(Event.COMPLETE, onLoadComplete);
this.s.addEventListener(Event.ID3, onID3);
this.s.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
this.s.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onIOError);
Rilevamento dell’input
dell’utente
21
Questo capitolo descrive come creare l’interattività utilizzando ActionScript 3.0 per
rispondere all’attività da parte dell’utente. Descrive gli eventi da tastiera e del mouse, quindi
passa ad argomenti più avanzati, tra cui la personalizzazione del menu di scelta di rapida e la
gestione degli elementi attivi. Il capitolo si chiude con WordSearch, un esempio di
applicazione che risponde all’input del mouse.
Il capitolo presuppone una certa dimestichezza con il modello di eventi ActionScript 3.0. Per
ulteriori informazioni, vedere Capitolo 10, “Gestione degli eventi” a pagina 335.
Sommario
Elementi fondamentali dell’input dell’utente. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 671
Rilevamento dell’input da tastiera. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 674
Rilevamento dell’input da mouse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 676
Esempio: WordSearch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .682
671
La classe InteractiveObject è una sottoclasse della classe DisplayObject e fornisce la struttura
comune di eventi e funzionalità necessaria per gestire l’interazione dell’utente. Non è possibile
creare direttamente un’istanza della classe InteractiveObject. Gli oggetti di visualizzazione
come SimpleButton, Sprite, TextField e vari componenti di Flash e Flex ereditano il modello
di interazione dell’utente da questa classe e pertanto condividono una struttura comune.
Ciò significa che le tecniche illustrate e il codice scritto per gestire l’interazione dell’utente in
un oggetto derivato da InteractiveObject sono validi per tutti gli altri.
Le seguenti operazioni comuni correlate all’interazione dell’utente sono descritte in questo
capitolo:
■ Rilevamento dell’input da tastiera a livello dell’intera applicazione
■ Acquisizione dell’input da tastiera in un oggetto di visualizzazione specifico
■ Rilevamento dell’input da mouse a livello dell’intera applicazione
■ Acquisizione dell’input da mouse in un oggetto di visualizzazione specifico
■ Creazione di un’interattività di trascinamento della selezione
■ Creazione di un cursore del mouse (puntatore del mouse) personalizzato
■ Aggiunta di nuovi comportamenti al menu di scelta rapida
■ Gestione degli elementi attivi
Alcuni tasti, ad esempio Ctrl, generano eventi anche se sono privi di rappresentazione sotto
forma di glifo.
Nel codice di esempio precedente, il listener di eventi da tastiera rileva l’input da tastiera per
l’intero stage. È anche possibile scrivere un listener di eventi per un oggetto di visualizzazione
specifico sullo stage; questo evento viene attivato quando l’oggetto è l’elemento attivo.
Nell’esempio seguente, i comandi da tastiera sono visualizzati nel pannello Output solo
quando l’utente digita all’interno dell’istanza TextField. Se si tiene premuto il tasto Maiusc, il
bordo dell’istanza TextField diventa temporaneamente rosso.
Questo codice presuppone che sullo stage sia presente un’istanza TextField di nome tf.
tf.border = true;
tf.type = "input";
tf.addEventListener(KeyboardEvent.KEY_DOWN,reportKeyDown);
tf.addEventListener(KeyboardEvent.KEY_UP,reportKeyUp);
function reportKeyDown(event:KeyboardEvent):void
{
trace("Key Pressed: " + String.fromCharCode(event.charCode) +
" (key code: " + event.keyCode + " character code: "
+ event.charCode + ")");
if (event.keyCode == Keyboard.SHIFT) tf.borderColor = 0xFF0000;
}
function reportKeyUp(event:KeyboardEvent):void
{
trace("Key Released: " + String.fromCharCode(event.charCode) +
" (key code: " + event.keyCode + " character code: " +
event.charCode + ")");
if (event.keyCode == Keyboard.SHIFT)
{
tf.borderColor = 0x000000;
}
}
Per le mappature tra i tasti e i relativi valori dei codici di carattere in ASCII, vedere
Appendice C, “Tasti della tastiera e valori dei codici tasto” a pagina 761.
Le mappature tra tasti e i relativi codici tasto dipendono dal dispositivo e dal sistema
operativo. Per tale motivo, è consigliabile non utilizzare le mappature dei tasti per attivare
azioni. Invece, utilizzare i valori di costante predefiniti forniti dalla classe Keyboard per fare
riferimento alle proprietà keyCode appropriate. Ad esempio, anziché utilizzare la mappatura
per il tasto Maiusc, utilizzare la costante Keyboard.SHIFT (come mostrato nel codice di
esempio precedente).
function reportKeyDown(event:KeyboardEvent):void
{
trace(event.currentTarget.name + " hears key press: " +
String.fromCharCode(event.charCode) + " (key code: " +
event.keyCode + " character code: " + event.charCode + ")");
}
Poiché è presente un listener sia sul campo di testo che sul relativo contenitore superiore, la
funzione reportKeyDown() viene chiamata due volte per ogni comando da tastiera all’interno
di TextField. Si noti che per ogni tasto premuto, il campo di testo invia un evento prima del
clip filmato container.
Il sistema operativo e il browser Web elaborano gli eventi da tastiera prima di Adobe Flash
Player. Ad esempio, in Microsoft Internet Explorer, se si preme Ctrl+W viene chiusa la
finestra del browser prima che l’eventuale file SWF in essa contenuto invii un evento da
tastiera.
stage.addEventListener(MouseEvent.CLICK, reportClick);
function reportClick(event:MouseEvent):void
{
trace(event.currentTarget.toString() +
" dispatches MouseEvent. Local coords [" +
event.localX + "," + event.localY + "] Stage coords [" +
event.stageX + "," + event.stageY + "]");
}
Nell’esempio precedente, si noti che l’evento mouse contiene le informazioni sul clic. Le
proprietà localX e localY contengono la posizione del clic sull’elemento di livello più basso
nella catena di visualizzazione. Ad esempio, se si fa clic sull’angolo in alto a sinistra di square
vengono visualizzate le coordinate locali [0,0], dal momento che si tratta del punto di
registrazione di square. In alternativa, le proprietà stageX e stageY fanno riferimento alle
coordinate globali del clic sullo stage. Lo stesso clic visualizza [50,50] per queste coordinate,
dal momento che square è stato spostato in corrispondenza di queste coordinate. Entrambe
queste coppie di coordinate possono essere utili a seconda del tipo di risposta che si desidera
dare all’interazione dell’utente.
L’oggetto MouseEvent contiene le proprietà booleane altKey, ctrlKey e shiftKey, che
possono essere utilizzate per verificare se al momento del clic del mouse viene premuto anche
il tasto Alt, Ctrl o Maiusc.
addChild(target1);
addChild(target2);
addChild(circle);
circle.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown)
function mouseDown(event:MouseEvent):void
{
circle.startDrag();
}
circle.addEventListener(MouseEvent.MOUSE_UP, mouseReleased);
function mouseReleased(event:MouseEvent):void
{
circle.stopDrag();
trace(circle.dropTarget.name);
}
stage.addEventListener(MouseEvent.MOUSE_MOVE,redrawCursor);
Mouse.hide();
function redrawCursor(event:MouseEvent):void
{
cursor.x = event.stageX;
cursor.y = event.stageY;
}
function changeColor(event:ContextMenuEvent):void
{
square.transform.colorTransform = getRandomColor();
}
function getRandomColor():ColorTransform
{
return new ColorTransform(Math.random(), Math.random(),
Math.random(),1,(Math.random() * 512) - 255,
(Math.random() * 512) -255, (Math.random() * 512) - 255, 0);
}
Lo strumento di creazione di Flash utilizza delle scelte rapide da tastiera per gestire gli
elementi attivi; pertanto è preferibile provare i file SWF in un browser anziché in Flash
per simulare correttamente la gestione degli elementi attivi.
Esempio: WordSearch
Questo esempio illustra l’interazione dell’utente mediante la gestione degli eventi del mouse.
Gli utenti creano il maggior numero possibile di parole partendo da una griglia casuale di
lettere e movendosi sia in orizzontale che in verticale all’interno della griglia, ma senza usare
mai la stessa lettera due volte. L’esempio illustra le seguenti funzioni di ActionScript 3.0:
■ Creazione dinamica di una griglia di componenti
■ Risposta agli eventi del mouse
■ Gestione di un punteggio in base all’interazione con l’utente
Per ottenere i file dell’applicazione per questo esempio, accedere all’indirizzo www.adobe.com/
go/learn_programmingAS3samples_flash_it. I file dell’applicazione WordSearch si trovano
nella cartella Samples/WordSearch. L’applicazione è costituita dai seguenti file:
File Descrizione
WordSearch.as La classe che fornisce la funzionalità principale
dell’applicazione.
Generazione di un tabellone
Il tabellone di gioco è una griglia di lettere casuali. Nella funzione generateBoard() viene
creata una griglia bidimensionale nidificando un ciclo all’interno di un altro. Il primo ciclo
incrementa le righe mentre il secondo incrementa il numero totale di colonne per riga.
Ognuna delle celle create da queste righe e colonne contiene un pulsante che rappresenta una
lettera sul tabellone.
private function generateBoard(startX:Number,
startY:Number,
totalRows:Number,
totalCols:Number,
buttonSize:Number):void
{
buttons = new Array();
var colCounter:uint;
var rowCounter:uint;
for (rowCounter = 0; rowCounter < totalRows; rowCounter++)
{
buttons.push(b);
}
}
}
Benché venga aggiunto un listener per un evento MouseEvent.CLICK su una sola riga, dal
momento che si trova in un ciclo for, viene assegnato a ogni istanza di Button. Inoltre, a ogni
pulsante viene assegnato un nome derivante dalla sua posizione di riga e colonna, al fine di
facilitare il riferimento alla riga e alla colonna di ogni pulsante più avanti nel codice.
Questa funzione scorre tutte le parole presenti nel dizionario. Se la parola dell’utente
corrisponde a una parola presente nel dizionario, ne viene restituita la posizione nel
dizionario. Il metodo submitWord() verifica a questo punto la risposta e, se la posizione è
valida, aggiorna il punteggio.
Connettività di rete e
comunicazioni
22
In questo capitolo viene descritto come attivare il file SWF affinché possa comunicare con i
file esterni e altre istanze di Adobe Flash Player 9. Viene inoltre spiegato come caricare dati da
origini esterne, inviare messaggi tra un server Java e Flash Player ed eseguire il caricamento e lo
scaricamento di file utilizzando le classi FileReference e FileReferenceList.
Sommario
Nozioni fondamentali sulla connettività di rete e le comunicazioni . . . . . . . . . . . . . 687
Operazioni con i dati esterni. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 691
Connessione ad altre istanze di Flash Player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .698
Connessioni socket . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .705
Memorizzazione di dati locali. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 711
Operazioni di caricamento e scaricamento dei file . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
Esempio: Creazione di un client Telnet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 726
Esempio: Caricamento e scaricamento di file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .730
687
In ActionScript 3.0, è possibile caricare file esterni con le classi URLLoader e URLRequest.
Quindi, si utilizza una classe specifica per accedere ai dati, a seconda del tipo di dati che sono
stati caricati. Ad esempio, se il contenuto remoto è formattato come coppie nome-valore,
utilizzare la classe URLVariables per analizzare i risultati del server. In alternativa, se il file
caricato mediante le classi URLLoader e URLRequest è un documento XML remoto, sarà
possibile analizzare il documento XML utilizzando la funzione di costruzione della classe
XML, la funzione di costruzione della classe XMLDocument o il metodo
XMLDocument.parseXML(). In questo modo è possibile semplificare il codice ActionScript
perché il codice per caricare i file esterni è lo stesso, indipendentemente dal fatto che si utilizzi
la classe URLVariables, la classe XML o un’altra classe per analizzare e utilizzare i dati remoti.
Il pacchetto flash.net contiene anche delle classi per altri tipi di comunicazione remota, tra cui
la classe FileReference per caricare e scaricare file da un server, le classi Socket e XMLSocket
che consentono di comunicare direttamente con i computer remoti mediante connessioni
socket e le classi NetConnection eNetStream che vengono utilizzate per comunicare con
risorse server specifiche di Flash (ad esempio, Flash Media Server e i server Flash Remoting) e
per caricare i file video.
Infine, il pacchetto flash.net include le classi per la comunicazione sul computer locale degli
utenti, tra cui la classe LocalConnection, che consente la comunicazione tra due o più file
SWF in esecuzione su un solo computer, e la classe SharedObject, che consente di
memorizzare i dati sul computer di un utente e recuperarli successivamente quando ritornano
all’applicazione.
Lo snippet di codice precedente crea un’istanza di XML di nome dataXML che contiene un
pacchetto XML da inviare al server. Vengono quindi impostate la proprietà contentType di
URLRequest su "text/xml" e la proprietà data di URLRequest sul contenuto del pacchetto
XML, che viene convertito in una stringa mediante il metodo XML.toXMLString(). Infine,
viene creata una nuova istanza di URLLoader e viene inviata la richiesta allo script remoto
utilizzando il metodo URLLoader.load().
Esistono tre modi per specificare i parametri da passare a una richiesta URL:
■ All’interno della funzione di costruzione URLVariables
■ All’interno del metodo URLVariables.decode()
■ Come proprietà specifiche all’interno dell’oggetto stesso URLVariables
Quando si definiscono le variabili all’interno della funzione di costruzione URLVariables o del
metodo URLVariables.decode(), è necessario assicurarsi di eseguire la codifica URL del
carattere e commerciale, in quanto ha un significato particolare e agisce come delimitatore.
Ad esempio, quando si passa una e commerciale, è necessario eseguire la codifica URL di
questo carattere modificandolo da & in %26, in quanto la e commerciale agisce come
delimitatore per i parametri.
Per impostazione predefinita, se non si definisce un metodo di richiesta Flash Player carica il
contenuto utilizzando il metodo HTTP GET. Se si desidera inviare i dati utilizzando il metodo
POST, impostare la proprietà request.method su POST utilizzando la costante statica
URLRequestMethod.POST, come descritto nel codice seguente:
var request:URLRequest = new URLRequest("sendfeedback.cfm");
request.method = URLRequestMethod.POST;
Il file contiene due parametri, monthNames e dayNames. Ogni parametro contiene un elenco
separato da virgole che viene analizzato come stringa. Questo elenco può essere suddiviso in
un array utilizzando il metodo String.split().
S U GG E R I M E N T O
Evitare di utilizzare parole riservate o costrutti del linguaggio come nomi di variabili nei
file di dati esterni, perché ciò rende più difficile la lettura e il debug del codice.
Ogni coppia nome-valore contenuta nel file esterno viene creata sotto forma di proprietà
nell’oggetto URLVariables. Ogni proprietà all’interno dell’oggetto variables nell’esempio di
codice precedente viene considerato come una stringa. Se il valore della coppia nome-valore è
un elenco di elementi, è possibile convertire la stringa in un array chiamando il metodo
String.split(), come riportato di seguito:
var dayNameArray:Array = variables.dayNames.split(",");
S UG G E R I ME N TO
Se si caricano dati numerici dai file di testo esterni, è necessario convertire i valori in
valori numerici utilizzando una funzione di primo livello quale int(), uint() o Number().
Anziché caricare il contenuto del file remoto come stringa e creare un nuovo oggetto
URLVariables, è possibile impostare la proprietà URLLoader.dataFormat su una delle
proprietà statiche presenti nella classe URLLoaderDataFormat. Di seguito sono riportati i tre
valori possibili per la proprietà URLLoader.dataFormat:
■ URLLoaderDataFormat.BINARY — La proprietà URLLoader.data conterrà dati binari
memorizzati nell’oggetto ByteArray.
■ URLLoaderDataFormat.TEXT — La proprietà URLLoader.data conterrà del testo in un
oggetto String.
■ URLLoaderDataFormat.VARIABLES — La proprietà URLLoader.data conterrà le
variabili con codifica URL memorizzate in un oggetto URLVariables.
function completeHandler(event:Event):void
{
trace(event.target.data.welcomeMessage);
}
Classe LocalConnection
La classe LocalConnection consente di sviluppare file SWF in grado di inviare istruzioni ad
altri file SWF senza utilizzare il metodo fscommand() o JavaScript. Gli oggetti
LocalConnection possono comunicare solo tra file SWF in esecuzione sullo stesso computer
client, tuttavia possono essere eseguiti in applicazioni diverse. Ad esempio, un file SWF in
esecuzione in un browser e un file SWF in esecuzione in un proiettore possono condividere le
informazioni: il proiettore gestisce le informazioni locali, mentre il file SWF basato su browser
si connette in remoto. Un proiettore è un file SWF salvato in un formato che può essere
eseguito come applicazione autonoma, ovvero senza richiedere l’installazione di Flash Player
essendo incorporato nell’eseguibile.
Gli oggetti LocalConnection possono essere utilizzati per la comunicazione tra file SWF che
utilizzano versioni diverse di ActionScript:
■ Gli oggetti LocalConnection di ActionScript 3.0 sono in grado di comunicare con gli
oggetti LocalConnection creati in ActionScript 1.0 e 2.0.
■ Gli oggetti LocalConnection di ActionScript 1.0 e 2.0 sono in grado di comunicare con
gli oggetti LocalConnection creati in ActionScript 3.0.
Flash Player gestisce in modo automatico questa comunicazione tra oggetti LocalConnection
di versioni diverse.
È possibile utilizzare gli oggetti LocalConnection per inviare e ricevere dati in un solo file
SWF; Adobe consiglia tuttavia di non utilizzare questo metodo, bensì di utilizzare gli
oggetti condivisi.
Sono disponibili tre modi per aggiungere metodi di callback agli oggetti LocalConnection:
■ Creare una sottoclasse della classe LocalConnection e aggiungere dei metodi.
■ Impostare la proprietà LocalConnection.client su un oggetto che implementi i
metodi.
■ Creare una classe dinamica per estendere LocalConnection e associare in modo dinamico i
metodi.
Il primo modo per aggiungere i metodi di callback consiste nell’estendere la classe
LocalConnection. Definire i metodi all’interno della classe personalizzata anziché aggiungerli
in modo dinamico all’istanza di LocalConnection. Questo approccio viene illustrato nel
codice riportato di seguito:
package
{
import flash.net.LocalConnection;
public class CustomLocalConnection extends LocalConnection
{
public function CustomLocalConnection(connectionName:String)
{
try
{
connect(connectionName);
}
catch (error:ArgumentError)
{
// Server già creato/connesso
}
}
Per creare una nuova istanza della classe DynamicLocalConnection, è possibile utilizzare il
codice riportato di seguito:
var serverLC:CustomLocalConnection;
serverLC = new CustomLocalConnection("serverName");
Il terzo modo per aggiungere i metodi di callback, creando una classe dinamica e associando in
modo dinamico i metodi, è molto simile all’utilizzo della classe LocalConnection nelle
versioni precedenti di ActionScript, come illustrato nel codice riportato di seguito:
import flash.net.LocalConnection;
dynamic class DynamicLocalConnection extends LocalConnection {}
Il precedente modo di aggiungere i metodi di callback non è consigliato, perché il codice non
è molto portabile. Inoltre, l’utilizzo di questo metodo per la creazione delle connessioni locali
potrebbe causare problemi a livello di prestazioni perché l’accesso alle proprietà dinamiche è
significativamente più lento dell’accesso alle proprietà chiuse.
Classe Socket
Introdotta in ActionScript 3.0, la classe Socket consente di effettuare connessioni socket e di
leggere e scrivere dati binari originari da ActionScript. È simile alla classe XMLSocket ma non
impone il formato dei dati ricevuti e trasmessi. La classe Socket è utile per interagire con i
server che utilizzano protocolli binari. Utilizzando le connessioni socket binarie è possibile
scrivere codice che consenta l’interazione con più protocolli Internet diversi, ad esempio
POP3, SMTP, IMAP e NNTP. Ciò consente a Flash Player di connettersi a propria volta ai
server di posta e delle news.
Classe XMLSocket
ActionScript fornisce una classe XMLSocket incorporata che consente di stabilire una
connessione continua con un server. La connessione aperta evita problemi di latenza e viene in
genere utilizzata per applicazioni in tempo reale, ad esempio per le applicazioni chat o i giochi
in modalità multiplayer. Una normale soluzione chat basata su HTTP esegue il polling del
server e scarica i nuovi messaggi mediante una richiesta HTTP. Al contrario, una soluzione
chat basata su XMLSocket mantiene una connessione aperta con il server, che consente a
quest’ultimo di inviare immediatamente i messaggi in entrata senza che il client emetta una
richiesta.
Per creare una connessione socket, è necessario creare un’applicazione sul lato server che
attenda la richiesta della connessione socket e invii la risposta al file SWF. Questo tipo di
applicazione sul lato server può essere scritta in un linguaggio di programmazione come Java,
Python o Perl. Per utilizzare la classe XMLSocket, sul server deve essere in esecuzione un
daemon in grado interpretare il protocollo utilizzato dalla classe XMLSocket. Il protocollo
viene descritto nell’elenco seguente:
■ I messaggi XML vengono inviati su una connessione socket di streaming TCP/IP full-
duplex.
■ Ogni messaggio XML è un documento XML completo, terminato da un byte zero (0).
Per trasferire il codice XML verso e dal server su una connessione socket, è possibile utilizzare
i metodi XMLSocket.connect() e XMLSocket.send() della classe XMLSocket. Il metodo
XMLSocket.connect() stabilisce una connessione socket con una porta di un server Web.
Il metodo XMLSocket.send() passa un oggetto XML al server specificato nella connessione
socket.
Quando si richiama il metodo XMLSocket.connect(), Flash Player apre una connessione
TCP/IP al server e la mantiene aperta fino al verificarsi di uno dei seguenti eventi:
■ Viene chiamato il metodo XMLSocket.close() della classe XMLSocket.
■ Non sono più presenti riferimenti all’oggetto XMLSocket.
■ Flash Player viene chiuso.
■ La connessione viene interrotta, ad esempio il modem si disconnette.
class SimpleServer
{
private static SimpleServer server;
ServerSocket socket;
Socket incoming;
BufferedReader readerIn;
PrintStream printOut;
try
{
port = Integer.parseInt(args[0]);
}
catch (ArrayIndexOutOfBoundsException e)
{
// Rileva l’eccezione e continua.
}
Se non è possibile avviare il server perché i file non si trovano nel percorso di classe
Java, provare ad avviarlo con java -classpath . SimpleServer.
Per inviare dati al server XMLSocket, utilizzare il metodo XMLSocket.send() e passare una
stringa o un oggetto XML. Flash Player converte il parametro fornito in un oggetto String e
invia il contenuto al server XMLSocket seguito da un byte zero (0):
xmlsock.send(xmlFormattedData);
Il metodo XMLSocket.send() non restituisce un valore che indica se i dati sono stati
trasmessi correttamente. Se si è verificato un errore mentre si tenta di inviare i dati, viene
generato un errore IOError.
S UG G E R I ME N T O
Ogni messaggio inviato al server socket XML deve essere terminato da un carattere
newline (\n).
Se non è possibile trovare un oggetto condiviso di nome test, ne viene creato uno nuovo con
dimensioni di 0 byte. Se l’oggetto condiviso esisteva in precedenza, vengono restituite le
dimensioni correnti (espresse in byte).
È possibile memorizzare dati in un oggetto condiviso assegnando dei valori all’oggetto dati,
come illustrato nell’esempio riportato di seguito:
var so:SharedObject = SharedObject.getLocal("test");
so.data.now = new Date().time;
trace(so.data.now);
trace("SharedObject is " + so.size + " bytes");
Il codice sopra riportato utilizza il parametro size per determinare se l’istanza dell’oggetto
condiviso con il nome specificato esiste già. Se si prova il codice riportato di seguito, si noterà
che l’oggetto condiviso viene ricreato ogni volta che si esegue il codice. Per salvare un oggetto
condiviso sul disco rigido dell’utente, è necessario chiamare in modo esplicito il metodo
SharedObject.flush() come illustrato nell’esempio riportato di seguito:
var so:SharedObject = SharedObject.getLocal("test");
if (so.size == 0)
{
// L’oggetto condiviso non esiste.
trace("created...");
so.data.now = new Date().time;
}
trace(so.data.now);
trace("SharedObject is " + so.size + " bytes");
so.flush();
Quando si utilizza il metodo flush() per scrivere gli oggetti condivisi sul disco rigido
dell’utente, verificare con attenzione se l’utente ha disattivato in modo esplicito la
memorizzazione locale tramite Gestione impostazioni di Flash Player
(www.macromedia.com/support/documentation/en/flashplayer/help/
settings_manager07.html), come illustrato nell’esempio riportato di seguito:
var so:SharedObject = SharedObject.getLocal("test");
trace("Current SharedObject size is " + so.size + " bytes.");
so.flush();
La prima volta che si esegue il codice sopra riportato, viene creata una nuova istanza di
SharedObject di nome test con dimensioni iniziali di 0 byte. Poiché le dimensioni iniziali
sono pari a 0 byte, l’istruzione if restituisce true e viene aggiunta una nuova proprietà di
nome now all’oggetto condiviso locale. La durata dell’oggetto condiviso viene calcolata
sottraendo il valore della proprietà now dall’ora corrente. A ogni successiva esecuzione del
codice sopra riportato, le dimensioni dell’oggetto condiviso dovrebbero essere maggiori di 0 e
il codice registrerà da quanti minuti è stato creato tale oggetto.
Indipendentemente dal valore di questo parametro, gli oggetti condivisi creati vengono presi
in considerazione per il conteggio dello spazio totale su disco concesso al dominio.
Un’istanza della classe FileReference può essere creata in due modi. È possibile utilizzare
l’operatore new come illustrato nel codice riportato di seguito:
import flash.net.FileReference;
var myFileReference:FileReference = new FileReference();
È possibile eseguire una sola azione browse() o download() alla volta, in quanto è
possibile aprire una sola finestra di dialogo per volta.
Lo script server che gestisce il caricamento del file deve prevedere una richiesta POST HTTP
con gli elementi seguenti:
■ Content-Type con un valore multipart/form-data.
■ Content-Disposition con un attributo name impostato su “Filedata” e un attributo
filename impostato sul nome del file originale. È possibile specificare un attributo name
personalizzato passando un valore per il parametro uploadDataFieldName nel metodo
FileReference.upload().
■ Il contenuto binario del file.
------------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
Content-Disposition: form-data; name="Filename"
sushi.jpg
------------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
Content-Disposition: form-data; name="Filedata"; filename="sushi.jpg"
Content-Type: application/octet-stream
Test File
------------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
Content-Disposition: form-data; name="Upload"
Submit Query
------------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
(actual file data,,,)
Il seguente esempio di richiesta POST HTTP invia tre variabili POST: api_sig, api_key e
auth_token e utilizza "photo" come valore personalizzato per il nome del campo dati di
caricamento:
POST /handler.asp HTTP/1.1
Accept: text/*
Content-Type: multipart/form-data;
boundary=----------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
User-Agent: Shockwave Flash
Host: www.mydomain.com
Content-Length: 421
Connection: Keep-Alive
Cache-Control: no-cache
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Filename"
sushi.jpg
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="api_sig"
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="auth_token"
XXXXXXXXXXXXXXXXXXXXXXX
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="photo"; filename="sushi.jpg"
Content-Type: application/octet-stream
Submit Query
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--
Per impostazione predefinita, la finestra di dialogo del selettore del sistema consente agli
utenti di selezionare qualsiasi tipo di file dal computer locale, tuttavia gli sviluppatori possono
specificare uno o più filtri per tipi di file personalizzati utilizzando la classe FileFilter e
passando un array di istanze di FileFilter al metodo browse():
var imageTypes:FileFilter = new FileFilter("Images (*.jpg, *.jpeg, *.gif,
*.png)", "*.jpg; *.jpeg; *.gif; *.png");
var textTypes:FileFilter = new FileFilter("Text Files (*.txt, *.rtf)",
"*.txt; *.rtf");
var allTypes:Array = new Array(imageTypes, textTypes);
var fileRef:FileReference = new FileReference();
fileRef.browse(allTypes);
Flash Player non offre il supporto completo per i server che richiedono l’autenticazione.
Solo i file SWF in esecuzione in un browser (ovvero quelli che utilizzano il plug-in per il
browser o il controllo Microsoft ActiveX®) possono fornire una finestra di dialogo per
richiedere all’utente di immettere un nome utente e una password per l’autenticazione, e
solo per gli scaricamenti. Per i caricamenti mediante il plug-in o il controllo ActiveX o per
il caricamento/scaricamento mediante un lettore autonomo o esterno, il trasferimento
dei file non è possibile.
Se si crea uno script server in ColdFusion per accettare il caricamento di un file da Flash
Player, è possibile utilizzare codice analogo a quello riportato di seguito:
<cffile action="upload" filefield="Filedata" destination="#ExpandPath('./
')#" nameconflict="OVERWRITE" />
Nell’esempio precedente viene creato un nuovo oggetto URLVariables che viene passato allo
script sul lato server remoto. Nelle versioni precedenti di ActionScript era possibile passare
variabili allo script di caricamento sul server mediante valori inclusi nella stringa di query.
ActionScript 3.0 consente di passare le variabili allo script remoto utilizzando un oggetto
URLRequest, che consente di passare i dati utilizzando il metodo POST o GET; in questo modo
diventa inoltre più semplice passare set di dati più estesi. Per specificare se le variabili vengono
passate utilizzando il metodo di richiesta GET o POST, è possibile impostare la proprietà
URLRequest.method rispettivamente su URLRequestMethod.GET o su
URLRequestMethod.POST.
La capacità di rinominare un file può risultare molto utile se il nome file del server non è
intuitivo o è stato generato dal server. È inoltre opportuno specificare il parametro
defaultFileName quando si scarica un file utilizzando uno script sul lato server, anziché
direttamente. Ad esempio, è necessario specificare il parametro defaultFileName se si
utilizza uno script sul lato server che scarica i file in base alle variabili URL passate.
Diversamente, il nome predefinito del file scaricato corrisponde al nome dello script sul lato
server.
Il codice riportato di seguito illustra lo script ColdFusion, download.cfm, che scarica uno dei
due file dal server, a seconda del valore di una variabile URL:
<cfparam name="URL.id" default="1" />
<cfswitch expression="#URL.id#">
<cfcase value="2">
<cfcontent type="text/plain" file="#ExpandPath('two.txt')#"
deletefile="No" />
</cfcase>
<cfdefaultcase>
<cfcontent type="text/plain" file="#ExpandPath('one.txt')#"
deletefile="No" />
</cfdefaultcase>
</cfswitch>
function selectHandler(event:Event):void
{
var request:URLRequest = new URLRequest("http://www.[yourdomain].com/
fileUploadScript.cfm");
var file:FileReference;
var files:FileReferenceList = FileReferenceList(event.target);
var selectedFileArray:Array = files.fileList;
for (var i:uint = 0; i < selectedFileArray.length; i++)
{
file = FileReference(selectedFileArray[i]);
file.addEventListener(Event.COMPLETE, completeHandler);
try
{
file.upload(request);
}
File Descrizione
TelnetSocket.mxml Il file dell’applicazione principale costituito
dall’interfaccia utente MXML.
La prima variabile, serverURL, contiene l’indirizzo del server a cui connettersi specificato
dall’utente.
La seconda variabile, portNumber, specifica il numero di porta su cui è attualmente in
esecuzione il server Telnet. Per impostazione predefinita, il servizio Telnet viene eseguito sulla
porta 23e.
La terza variabile, socket, è un’istanza di Socket che tenterà di connettersi al server definito
dalle variabili serverURL e portNumber.
La quarta variabile, ta, è un riferimento a un’istanza del componente TextArea sullo stage.
Questo componente viene utilizzato per visualizzare le risposte dal server Telnet remoto o gli
eventuali messaggi di errore.
La variabile finale, state, è un valore numerico che viene utilizzato per determinare le opzioni
supportate dal client Telnet.
Come è già stato illustrato in precedenza, la funzione di costruzione della classe Telnet viene
chiamata dal metodo connect() nel file dell’applicazione principale.
La funzione di costruzione Telnet accetta tre parametri: server, port e output. I parametri
server e port specificano il nome del server e il numero di porta su cui è in esecuzione il
server Telnet. Il parametro finale, output, è un riferimento a un’istanza del componente
TextArea sullo stage dove verrà visualizzato l’output del server.
public function Telnet(server:String, port:int, output:TextArea)
{
serverURL = server;
portNumber = port;
ta = output;
socket = new Socket();
socket.addEventListener(Event.CONNECT, connectHandler);
socket.addEventListener(Event.CLOSE, closeHandler);
socket.addEventListener(ErrorEvent.ERROR, errorHandler);
socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
socket.addEventListener(ProgressEvent.SOCKET_DATA, dataHandler);
Security.loadPolicyFile("http://" + serverURL + "/crossdomain.xml");
try
{
msg("Trying to connect to " + serverURL + ":" + portNumber + "\n");
socket.connect(serverURL, portNumber);
}
Questo metodo viene chiamato dal metodo sendCommand() del file dell’applicazione
principale.
Se il contenuto del componente TextArea non scorre automaticamente fino alla fine, gli utenti
dovranno trascinare manualmente le barre di scorrimento nell’area di testo per visualizzare
l’ultima risposta dal server.
File Descrizione
FileIO.fla Il file principale dell’applicazione in Flash (FLA)
oppure o Flex (MXML)
FileIO.mxml
Il codice riportato di seguito illustra il pannello di caricamento dei file che contiene una barra
di avanzamento e due pulsanti. Il primo pulsante, startUpload, chiama il metodo
FileUpload.startUpload(), che a propria volta chiama il metodo
FileReference.browse(). Di seguito è riportato un estratto del codice per il pannello di
caricamento dei file:
<mx:Panel title="Upload File" paddingTop="10" paddingBottom="10"
paddingLeft="10" paddingRight="10">
<mx:ProgressBar id="uploadProgress" label="" mode="manual" />
<mx:ControlBar horizontalAlign="right">
<mx:Button id="startUpload" label="Upload..."
click="fileUpload.startUpload();" />
<mx:Button id="cancelUpload" label="Cancel"
click="fileUpload.cancelUpload();" enabled="false" />
</mx:ControlBar>
</mx:Panel>
Questo codice colloca un’istanza del componente ProgressBar e due istanze del componente
Button sullo stage. Quando l’utente fa clic sul pulsante di caricamento (startUpload), viene
aperta una finestra di dialogo del sistema operativo che consente all’utente di selezionare un
file da caricare su un server remoto. L’altro pulsante, cancelUpload, è disattivato per
impostazione predefinita, tuttavia quando un utente inizia il caricamento di un file, il
pulsante viene attivato e consente di interrompere il trasferimento del file in qualsiasi
momento.
Questo codice è molto simile a quello utilizzato per il caricamento dei file. Quando l’utente fa
clic sul pulsante di scaricamento, (startDownload), viene chiamato il metodo
FileDownload.startDownload() che inizia lo scaricamento del file specificato nella variabile
FileDownload.DOWNLOAD_URL. Mentre il file viene scaricato, la barra di avanzamento viene
aggiornata e mostra la percentuale del file già scaricata. L’utente può annullare lo scaricamento
in qualsiasi momento facendo clic sul pulsante cancelDownload, che interrompe
immediatamente l’avanzamento dell’operazione.
/**
* Crea un’istanza di FileReference per gestire lo scaricamento del file.
*/
private var fr:FileReference;
/**
* Definisce il riferimento al componente ProgressBar di scaricamento.
*/
private var pb:ProgressBar;
La prima variabile, DOWNLOAD_URL, contiene il percorso del file che viene scaricato nel
computer dell’utente quando quest’ultimo fa clic sul pulsante di scaricamento nel file
dell’applicazione principale.
La seconda variabile, fr, è un oggetto FileReference che viene inizializzato nel metodo
FileDownload.init() e gestisce lo scaricamento del file remoto nel computer dell’utente.
Le ultime due variabili, pb e btn, contengono i riferimenti alle istanze dei componenti
ProgressBar e Button sullo stage, che vengono inizializzate dal metodo
FileDownload.init().
fr = new FileReference();
fr.addEventListener(Event.OPEN, openHandler);
fr.addEventListener(ProgressEvent.PROGRESS, progressHandler);
fr.addEventListener(Event.COMPLETE, completeHandler);
}
Il metodo openHandler() imposta il formato di testo per la proprietà label del componente
ProgressBar e attiva il pulsante di annullamento che consente all’utente di arrestare
immediatamente lo scaricamento in corso. Di seguito è riportato il metodo openHandler():
/**
* Quando viene inviato l’evento OPEN, modificare l’etichetta della barra
* di avanzamento e attivare il pulsante di annullamento che consente
* all’utente di interrompere l’operazione di scaricamento.
*/
private function openHandler(event:Event):void
{
pb.label = "DOWNLOADING %3%%";
btn.enabled = true;
}
L’evento progress ha due proprietà, bytesLoaded e bytesTotal, che vengono utilizzate per
aggiornare il componente ProgressBar sullo stage e mostrano all’utente la quantità di file
scaricata rispetto alla quantità rimanente. L’utente può interrompere il trasferimento del file in
qualsiasi momento facendo clic sul pulsante di annullamento sotto la barra di avanzamento.
Se il file viene scaricato correttamente, l’evento complete (Event.COMPLETE) richiama il
metodo completeHandler(), che comunica all’utente che lo scaricamento del file è stato
completato e disattiva il pulsante di annullamento. Di seguito è riportato il codice per il
metodo completeHandler():
/**
* Una volta completato lo scaricamento, modificare per l’ultima volta
* l’etichetta della barra di avanzamento e disabilitare il pulsante
* "Annulla", poiché lo scaricamento è già stato completato.
*/
private function completeHandler(event:Event):void
{
pb.label = "DOWNLOAD COMPLETE";
btn.enabled = false;
}
fr = new FileReference();
fr.addEventListener(Event.SELECT, selectHandler);
fr.addEventListener(Event.OPEN, openHandler);
fr.addEventListener(ProgressEvent.PROGRESS, progressHandler);
fr.addEventListener(Event.COMPLETE, completeHandler);
}
Dopo che l’utente ha selezionato un file da caricare, viene inviato l’evento select
(Event.SELECT) che richiama il metodo selectHandler(). Il metodo selectHandler()
crea un nuovo oggetto URLRequest e imposta la proprietà URLRequest.url sul valore dalla
costante UPLOAD_URL definito precedentemente nel codice. Infine, l’oggetto FileReference
carica il file selezionato nello script sul lato server specificato. Di seguito è riportato il codice
per il metodo selectHandler():
private function selectHandler(event:Event):void
{
var request:URLRequest = new URLRequest();
request.url = UPLOAD_URL;
fr.upload(request);
}
Sommario
Nozioni fondamentali sull’ambiente del sistema client. . . . . . . . . . . . . . . . . . . . . . . .739
Uso della classe System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .742
Uso della classe Capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .744
Uso della classe ApplicationDomain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .745
Uso della classe IME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .749
Esempio: Rilevamento delle caratteristiche del sistema . . . . . . . . . . . . . . . . . . . . . .755
739
■ Creazione di siti multilingua mediante l’IME
■ Interazione con il contenitore di Flash Player (che può essere una pagina HTML o
un’applicazione contenitore)
■ Salvataggio delle informazioni negli Appunti dell’utente
l pacchetto flash.system include inoltre le classi IMEConversionMode e SecurityPanel, che
contengono delle costanti statiche utilizzate rispettivamente con le classi IME e Security.
Se si desidera inviare le caratteristiche del sistema dell’utente a uno script sul lato server, in
modo che le informazioni possano essere memorizzate in un database, è possibile utilizzare il
codice ActionScript riportato di seguito:
var url:String = "log_visitor.cfm";
var request:URLRequest = new URLRequest(url);
request.method = URLRequestMethod.POST;
request.data = new URLVariables(Capabilities.serverString);
var loader:URLLoader = new URLLoader(request);
Dominio applicazione 1
application1.swf mx.core.Application
module1.swf
Loader Uso B
Modulo
Dominio applicazione 2
mx.core.Application Uso A
application2.swf
Modulo
Il file dell’applicazione principale è application1.swf. Contiene gli oggetti Loader che caricano
il contenuto da altri file SWF. In questo scenario, il dominio corrente è Dominio applicazione
1. Uso A, Uso B e Uso C illustrano le diverse tecniche per impostare il dominio
dell’applicazione appropriato per ogni file SWF incluso in un’applicazione.
Uso A: separazione in partizioni del file SWF secondario creando un dominio di sistema
secondario. Nel diagramma viene creato Dominio applicazione 2 come elemento secondario
del dominio di sistema. Il file application2.swf viene caricato nel Dominio applicazione 2 e le
relative definizioni di classe vengono in tal modo separate in partizioni dalle classi definite nel
file application1.swf.
Questa tecnica può essere utilizzata, ad esempio, per fare in modo che un’applicazione datata
carichi dinamicamente una versione più recente della stessa applicazione senza creare conflitti.
Il conflitto non avviene perché nonostante vengano utilizzati gli stessi nomi di classe, questi
sono separati in partizioni in domini dell’applicazione diversi.
Uso B: aggiunta di nuove definizioni di classe alle definizioni di classe correnti. Il dominio
dell’applicazione del file module1.swf è impostato sul dominio corrente (Dominio
applicazione 1). Ciò consente di aggiungere le nuove definizioni di classe all’attuale set di
definizioni di classe dell’applicazione. Questo approccio può essere utilizzato per una libreria
condivisa in runtime dell’applicazione principale. Il file SWF caricato viene gestito come una
libreria condivisa remota (RSL). Utilizzare questa tecnica per caricare le RSL mediante un
precaricatore prima dell’avvio dell’applicazione.
Il codice riportato di seguito imposta un dominio dell’applicazione sul dominio corrente:
request.url = "module1.swf";
request.applicationDomain = ApplicationDomain.currentDomain;
Se sul computer dell’utente non è stato attivato alcun IME, le chiamate ai metodi o alle
proprietà IME diversi da Capabilities.hasIME avranno esito negativo. Dopo che un IME
è stato attivato manualmente, le successive chiamate ActionScript ai metodi e alle
proprietà IME funzioneranno nei modi previsti. Ad esempio, se si utilizza un IME
giapponese, è necessario attivarlo prima di chiamare qualsiasi metodo o proprietà IME.
Il codice precedente controlla innanzi tutto se sul computer dell’utente è installato un IME
utilizzando la proprietà Capabilities.hasIME. Se questa proprietà è impostata su true, il
codice controlla quindi se l’IME dell’utente è attualmente attivato utilizzando la proprietà
IME.enabled.
Il codice precedente verifica come prima cosa se l’utente ha installato un IME. Quindi,
controlla quale modalità di conversione viene utilizzata dall’IME corrente, confrontando la
proprietà IME.conversionMode con ognuna delle costanti della classe IMEConversionMode.
Il codice precedente crea innanzitutto un campo di testo, che viene utilizzato per visualizzare
un messaggio di stato per l’utente. Quindi, se l’IME è installato, il codice attiva l’IME e
imposta la modalità di conversione sulla lingua coreana. Se nel computer dell’utente non è
installato l’IME per il coreano, viene generato un errore che viene rilevato dal blocco
try..catch. Il blocco try..catch visualizza il messaggio di errore nel campo di testo creato
in precedenza.
phoneTxt.type = TextFieldType.INPUT;
phoneTxt.addEventListener(FocusEvent.FOCUS_IN, focusInHandler);
phoneTxt.addEventListener(FocusEvent.FOCUS_OUT, focusOutHandler);
phoneTxt.restrict = "0-9";
phoneTxt.width = 100;
phoneTxt.height = 18;
phoneTxt.background = true;
phoneTxt.border = true;
addChild(phoneTxt);
nameField.type = TextFieldType.INPUT;
nameField.x = 120;
nameField.width = 100;
nameField.height = 18;
nameField.background = true;
nameField.border = true;
addChild(nameField);
function focusInHandler(event:FocusEvent):void
{
if (Capabilities.hasIME)
{
IME.enabled = false;
}
}
function focusOutHandler(event:FocusEvent):void
{
if (Capabilities.hasIME)
{
IME.enabled = true;
}
}
Questo esempio crea due campi di testo, phoneTxt e nameTxt, quindi aggiunge due listener
di eventi al campo di testo phoneTxt. Quando l’utente imposta l’attivazione sul campo di
testo phoneTxt, viene inviato un evento FocusEvent.FOCUS_IN e l’IME viene disattivato.
Quando il campo di testo phoneTxt non è più attivo, viene inviato l’evento
FocusEvent.FOCUS_OUT per riattivare l’IME.
if (Capabilities.hasIME)
{
IME.enabled = true;
try
{
IME.conversionMode = IMEConversionMode.JAPANESE_HIRAGANA;
}
catch (error:Error)
{
outputTxt.text = "Unable to change IME.";
}
System.ime.addEventListener(IMEEvent.IME_COMPOSITION,
imeCompositionHandler);
}
else
{
outputTxt.text = "Please install IME and try again.";
}
function imeCompositionHandler(event:IMEEvent):void
{
outputTxt.text = "you typed: " + event.text;
}
File Descrizione
CapabilitiesExplorer.fla Il file principale dell’applicazione in Flash (FLA)
oppure o Flex (MXML)
CapabilitiesExplorer.mxml
Se nell’ambiente utente corrente è disponibile l’API esterna, Flash Player chiama il metodo
JavaScript JS_getBrowserObjects(), che esegue delle elaborazioni cicliche dell’oggetto
navigator del browser e restituisce ad ActionScript una stringa di valori con codifica URL.
Questa stringa viene quindi convertita in un oggetto URLVariables (itemVars) e aggiunta
all’array itemArr, che viene restituito allo script chiamante.
Il codice inizia con la creazione di un array temporaneo che includerà tutte le coppie nome-
valore nell’oggetto navigator. Quindi, viene eseguita l’elaborazione ciclica dell’oggetto
navigator utilizzando un ciclo for..in e viene valutato il tipo di dati del valore corrente per
filtrare i valori indesiderati. In questa applicazione vengono utilizzati solo i valori di tipo
stringa o booleano, mentre gli altri tipi di dati (ad esempio, funzioni o array) vengono
ignorati. Ogni valore stringa o booleano nell’oggetto navigator viene aggiunto all’array
tempArr. Quindi, viene eseguita l’elaborazione ciclica dell’oggetto screen utilizzando un ciclo
for..in e ogni valore numerico viene aggiunto all’array tempArr. Infine, l’array temporaneo
viene convertito in una stringa utilizzando il metodo Array.join(). L’array utilizza la e
commerciale (&) come delimitatore, consentendo ad ActionScript di analizzare facilmente i
dati mediante la classe URLVariables.
Stampa 24
Adobe® Flash® Player 9 è in grado di comunicare con l’interfaccia di stampa di un sistema
operativo per inviare le pagine allo spooler di stampa. Ogni pagina inviata da Flash Player allo
spooler può includere contenuto visibile, dinamico o fuori schermo, inclusi i valori di
database e il testo dinamico. Inoltre, Flash Player imposta le proprietà della classe
flash.printing.PrintJob in base alle impostazioni della stampante dell’utente, in modo da
consentire la formattazione corretta delle pagine.
In questo capitolo vengono descritte in dettaglio le strategie per l’utilizzo dei metodi e delle
proprietà della classe flash.printing.PrintJob per creare un lavoro di stampa, leggere le
impostazioni di stampa di un utente e apportare modifiche a un lavoro di stampa in base al
feedback di Flash Player e del sistema operativo dell’utente.
Sommario
Elementi fondamentali della stampa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 762
Stampa di una pagina . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 764
Attività di Flash Player e interfaccia di stampa del sistema operativo . . . . . . . . . . 765
Impostazione delle dimensioni, della scala e dell’orientamento. . . . . . . . . . . . . . . . 768
Esempio: Stampa su più pagine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 771
Esempio: Modifica in scala, ritaglio e risposta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 773
761
Elementi fondamentali della stampa
762 Stampa
Concetti e termini importanti
L’elenco di riferimento seguente contiene dei termini importanti che vengono citati in questo
capitolo:
■ Spooler: una porzione del sistema operativo o del driver della stampante che tiene traccia
delle pagine mentre sono in attesa di essere stampate e le invia alla stampante quando
quest’ultima si rende disponibile.
■ Orientamento della pagina: la rotazione del contenuto stampato rispetto alla carta
(orizzontale o verticale).
■ Lavoro di stampa: la pagina o la serie di pagine che compongono un’unica stampa.
Questo esempio è destinato a illustrare gli elementi di base di uno script per un lavoro di
stampa e non contiene codice per la gestione degli errori. Per creare uno script che
risponda correttamente all’operazione di annullamento di un lavoro di stampa, vedere
“Operazioni relative alle eccezioni e ai valori restituiti” a pagina 765.
Se, per qualsiasi motivo, è necessario cancellare le proprietà di un oggetto PrintJob, impostare
la variabile PrintJob su null (come in myPrintJob = null).
764 Stampa
Attività di Flash Player e interfaccia di
stampa del sistema operativo
Poiché Flash Player invia le pagine all’interfaccia di stampa del sistema operativo, è opportuno
comprendere l’ambito delle attività gestite da Flash Player e quello delle attività gestite
dall’interfaccia di stampa del sistema operativo. Flash Player può avviare un lavoro di stampa,
leggere alcune delle impostazioni della pagina di una stampante, passare il contenuto per un
lavoro di stampa al sistema operativo e verificare se l’utente o il sistema ha annullato un lavoro
di stampa. Tutti gli altri processi, ad esempio la visualizzazione delle finestre di dialogo
specifiche della stampante, l’annullamento di un lavoro di stampa elaborato dallo spooler o la
segnalazione dello stato della stampante, vengono gestiti dal sistema operativo. Flash Player è
in grado di rispondere se si verificano problemi all’avvio o durante la formattazione di un
lavoro di stampa, ma può fornire una segnalazione solo su determinate proprietà o condizioni
dall’interfaccia di stampa del sistema operativo. Gli sviluppatori dovranno fare in modo che il
codice abbia la capacità di rispondere a queste proprietà o condizioni.
766 Stampa
Operazioni con le proprietà della pagina
Dopo che l’utente ha fatto clic su OK nella finestra di dialogo di stampa e PrintJob.start()
ha restituito true, è possibile accedere alle proprietà definite nelle impostazioni della
stampante, che includono la larghezza e l’altezza del foglio (pageHeight e pageWidth) e
l’orientamento del contenuto sul foglio. Poiché queste sono impostazioni della stampante, che
non vengono controllate da Flash Player, non è possibile modificarle; tuttavia, possono essere
utilizzate per allineare il contenuto inviato alla stampante, in modo che corrisponda alle
impostazioni correnti. Per ulteriori informazioni, vedere “Impostazione delle dimensioni,
della scala e dell’orientamento” a pagina 768.
Se non si specifica un valore per il terzo parametro, il lavoro di stampa utilizza l’impostazione
predefinita, ovvero la stampa vettoriale.
N OT A
768 Stampa
Utilizzo di rettangoli per l’area di stampa
Il metodo PrintJob.addPage() consente di specificare l’area di uno sprite che si desidera
stampare. Il secondo parametro, printArea, è rappresentato da un oggetto Rectangle. Sono
disponibili tre opzioni per fornire un valore a questo parametro:
■ Creare un oggetto Rectangle con proprietà specifiche e quindi utilizzare il rettangolo nella
chiamata ad addPage(), come illustrato nell’esempio riportato di seguito:
private var rect1:Rectangle = new Rectangle(0, 0, 400, 200);
myPrintJob.addPage(sheet, rect1);
■ Se non è già stato specificato un oggetto Rectangle, è possibile effettuare questa operazione
all’interno della chiamata, come illustrato nell’esempio riportato di seguito:
myPrintJob.addPage(sheet, new Rectangle(0, 0, 100, 100));
■ Se si prevede di specificare dei valori per il terzo parametro nella chiamata a addPage(),
ma senza specificare un rettangolo, è possibile utilizzare null come secondo parametro,
come riportato di seguito:
myPrintJob.addPage(sheet, null, options);
N OT A
770 Stampa
Inoltre, è possibile determinare le impostazioni dei margini della pagina confrontando le
dimensioni della pagina e del foglio, come nell’esempio riportato di seguito:
margin_height = (myPrintJob.paperHeight - myPrintJob.pageHeight) / 2;
margin_width = (myPrintJob.paperWidth - myPrintJob.pageWidth) / 2;
if (imgValue != null)
{
var img:Sprite = new Sprite();
img.graphics.beginFill(0xFFFFFF);
img.graphics.drawRect(imgValue.x, imgValue.y, imgValue.width,
imgValue.height);
img.graphics.endFill();
sheet.addChild(img);
}
sheet.addChild(txt);
}
sheet1.height = pj.pageHeight;
sheet1.width = pj.pageWidth;
sheet2.height = pj.pageHeight;
sheet2.width = pj.pageWidth;
try
{
pj.addPage(sheet1);
pagesToPrint++;
}
catch (error:Error)
{
// Risponde all’errore.
}
772 Stampa
try
{
pj.addPage(sheet2);
pagesToPrint++;
}
catch (error:Error)
{
// Risponde all’errore.
}
if (pagesToPrint > 0)
{
pj.send();
}
}
}
}
}
try
{
pj.addPage(this, new Rectangle(0, 0, 100, 100));
}
catch (error:Error)
{
// Non esegue alcuna azione.
}
pj.send();
}
else
{
txt.text = "Print job canceled";
}
// Reimposta le proprietà per la modifica in scala di txt.
txt.scaleX = 1;
txt.scaleY = 1;
}
774 Stampa
txt = new TextField();
txt.border = true;
txt.text = "Hello World";
}
Questo capitolo si concentra solo sulla comunicazione tra ActionScript in un file SWF e
l’applicazione contenitore che include un riferimento all’istanza di Flash Player in cui
l’SWF è caricato. Qualsiasi altro uso di Flash Player all’interno di un’applicazione non è
contemplato da questa documentazione. Flash Player è progettato per essere utilizzato
come plug-in per browser o come proiettore (applicazione autonoma). Altri scenari di
impiego potrebbero avere un supporto limitato.
Sommario
Nozioni fondamentali sull’uso dell’API esterna . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 778
Requisiti e vantaggi dell’API esterna . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 781
Uso della classe ExternalInterface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 783
Esempio: Uso dell’API esterna con una pagina Web contenitore . . . . . . . . . . . . . . 789
Esempio: Uso dell’API esterna con un contenitore ActiveX . . . . . . . . . . . . . . . . . . . 797
777
Nozioni fondamentali sull’uso dell’API
esterna
Se il nome fornito all’istanza di Flash Player in una pagina HTML (l’attributo id del tag
object) include un trattino (-) o altri caratteri che sono definiti come operatori in
JavaScript (ad esempio, +, *, /, \, . e così via), le chiamate a ExternalInterface da
ActionScript non funzionano quando la pagina Web contenitore viene visualizzata in
Internet Explorer.
Inoltre, se i tag HTML che definiscono l’istanza di Flash Player (i tag object ed embed)
sono nidificati in un tag form HTML, le chiamate ExternalInterface da ActionScript non
funzionano.
Se il contenitore è una pagina HTML, questo metodo richiama la funzione JavaScript con il
nome specificato, che deve essere definita in un elemento script presente nella pagina
HTML contenitore. Il valore restituito dalla funzione JavaScript viene ripassato ad
ActionScript.
<script language="JavaScript">
// Aggiunge due numeri e reinvia il risultato ad ActionScript
function addNumbers(num1, num2)
{
return (num1 + num2);
}
</script>
Il metodo addCallback() accetta due parametri: il primo, un nome di funzione quale una
stringa, è il nome con cui la funzione sarà conosciuta dal contenitore. Il secondo parametro è
la funzione ActionScript vera e propria che verrà eseguita quando il contenitore chiama il
nome di funzione definito. Dal momento che questi nomi sono distinti, è possibile specificare
un nome di una funzione che verrà utilizzata dal contenitore, anche se l’effettiva funzione
ActionScript ha un nome diverso. Si tratta di una possibilità particolarmente utile se non si
conosce il nome della funzione (ad esempio, se viene specificata una funzione anonima o se la
funzione da chiamare viene determinata in fase di runtime).
Il nodo radice è il nodo invoke e ha due attributi: name indica il nome della funzione da
chiamare, mentre returntype è sempre xml. Se la chiamata alla funzione comprende dei
parametri, il nodo invoke ha un nodo arguments secondario, i cui nodi secondari sono
costituiti dai valori di parametro formattati utilizzando il formato dei singoli valori illustrato
di seguito.
Quando si creano delle applicazioni che utilizzano l’API esterna con un’applicazione
contenitore ActiveX, probabilmente è più comodo scrivere un proxy che esegua l’operazione
di conversione delle chiamate alle funzioni native nel formato XML serializzato. Per un
esempio di una classe proxy scritta in C#, vedere “Funzionamento della classe
ExternalInterfaceProxy” a pagina 803.
Esempio: Uso dell’API esterna con una pagina Web contenitore 789
Per ottenere i file dell’applicazione per questo esempio, accedere all’indirizzo
www.adobe.com/go/learn_programmingAS3samples_flash_it. I file dell’applicazione
Introvert IM sono disponibili nella cartella Samples/IntrovertIM_HTML. L’applicazione è
costituita dai file seguenti:
File Descrizione
IntrovertIMApp.fla Il file principale dell’applicazione per Flash
oppure (FLA) o Flex (MXML).
IntrovertIMApp.mxml
Esempio: Uso dell’API esterna con una pagina Web contenitore 791
Innanzitutto, il codice verifica se l’API esterna è almeno disponibile nel contenitore corrente
utilizzando la proprietà ExternalInterface.available. In caso affermativo, inizia il
processo di impostazione della comunicazione. Poiché quando si tenta la comunicazione con
un’applicazione esterna possono verificarsi delle eccezioni di sicurezza e altri errori, il codice
viene racchiuso in un blocco try (i blocchi catch corrispondenti sono stati omessi dall’elenco
per ragioni di spazio).
Il codice successivo chiama il metodo isContainerReady(), rappresentato qui:
private function isContainerReady():Boolean
{
var result:Boolean = ExternalInterface.call("isReady");
return result;
}
Ogni volta che il metodo timerHandler() viene chiamato, verifica ancora una volta il
risultato del metodo isContainerReady(). Una volta inizializzato il contenitore, tale metodo
restituisce il valore true. A quel punto, il codice arresta il timer e chiama il metodo
setupCallbacks() per completare il processo di impostazione della comunicazione con il
browser.
Esempio: Uso dell’API esterna con una pagina Web contenitore 793
Esposizione dei metodi ActionScript a JavaScript
Come illustrava l’esempio precedente, quando il codice determina che il browser è pronto,
viene chiamato il metodo setupCallbacks(). Questo metodo prepara ActionScript alla
ricezione delle chiamate da JavaScript, come illustrato di seguito:
private function setupCallbacks():void
{
// Registra le funzioni client SWF con il contenitore
ExternalInterface.addCallback("newMessage", newMessage);
ExternalInterface.addCallback("getStatus", getStatus);
// Notifica al contenitore che il file SWF è pronto per essere chiamato.
ExternalInterface.call("setSWFIsReady");
}
È possibile passare parametri alle funzioni JavaScript anche utilizzando l’API esterna. Ad
esempio, considerare il metodo sendMessage() della classe IMManager, che viene chiamato
quando l’utente sta inviando un nuovo messaggio al proprio interlocutore:
public function sendMessage(message:String):void
{
ExternalInterface.call("newMessage", message);
}
Il codice verifica il valore della variabile swfReady, che rileva se il file SWF ha notificato il
browser che ne ha registrato i metodi con la classe ExternalInterface. Se il file SWF è pronto
per ricevere la comunicazione, la riga successiva (var currentStatus = ...) chiama di fatto il
metodo getStatus() nella classe IMManager. In questa riga di codice vengono eseguite tre
operazioni:
■ Viene chiamata la funzione JavaScript getSWF(), che restituisce un riferimento all’oggetto
JavaScript che rappresenta il file SWF. Il parametro passato a getSWF() determina quale
oggetto browser viene restituito nel caso in cui in una stessa pagina HTML sia presente
più di un solo file SWF. Il valore passato a tale parametro deve corrispondere all’attributo
id del tag object e all’attributo name del tag embed utilizzati per includere il file SWF.
Esempio: Uso dell’API esterna con una pagina Web contenitore 795
■ Utilizzando il riferimento al file SWF, viene chiamato il metodo getStatus() come se
fosse un metodo dell’oggetto SWF. In questo caso, viene utilizzato il nome di funzione
“getStatus” perché è il nome con cui la funzione ActionScript viene registrata mediante
ExternalInterface.addCallback().
■ Il metodo ActionScript getStatus() restituisce un valore. Tale valore viene assegnato alla
variabile currentStatus, che viene successivamente assegnata come contenuto
(la proprietà value) del campo di testo status.
File Descrizione
AppForm.cs Il file dell’applicazione principale, con
l’interfaccia C# Windows Forms.
L’oggetto evento (e) contiene una proprietà request (e.request) costituita da una stringa
che contiene le informazioni sulla chiamata alla funzione (ad esempio il nome della funzione e
i parametri) in formato XML. Queste informazioni possono essere utilizzate dal contenitore
per determinare quale codice eseguire. Nella classe ExternalInterfaceProxy, la richiesta viene
convertita dal formato XML a un oggetto ExternalInterfaceCall, che fornisce le stesse
informazioni in una forma più accessibile. Il metodo SetReturnValue() del controllo
ActiveX viene utilizzato per restituire il risultato di una funzione al chiamante ActionScript;
ancora una volta, il parametro risultante deve essere codificato nello stesso formato XML
utilizzato dall’API esterna.
Sommario
Sicurezza di Flash Player . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .807
Panoramica dei controlli di autorizzazione . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .811
Funzioni di sicurezza sandbox. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .822
Limitazioni delle API di connettività di rete . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .825
Sicurezza modalità a schermo intero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 827
Caricamento di contenuto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .828
Scambio di script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .832
Accesso a file multimediali caricati come dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .836
Caricamento di dati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 840
Caricamento di contenuto incorporato da file SWF importati in un dominio di
sicurezza. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .842
Operazioni con contenuto precedente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .843
Impostazione di autorizzazioni LocalConnection . . . . . . . . . . . . . . . . . . . . . . . . . . . .844
Controllo dell’accesso a script in una pagina Web host. . . . . . . . . . . . . . . . . . . . . . .845
Oggetti condivisi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .846
Accesso a fotocamera, microfono, Appunti, mouse e tastiera . . . . . . . . . . . . . . . . .848
807
Panoramica sulla sicurezza di
Flash Player
La maggior parte delle funzioni di sicurezza di Flash Player si basa sul dominio di origine dei
file SWF, multimediali e delle risorse caricati. Un file SWF di un dominio Internet specifico,
quale www.example.com, può sempre accedere ai dati di tale dominio. Tali risorse sono
inserite nello stesso raggruppamento di sicurezza, conosciuto come funzione di sicurezza
sandbox. Per ulteriori informazioni, vedere “Funzioni di sicurezza sandbox” a pagina 822.
Ad esempio, un file SWF può caricare altri file SWF, bitmap, file audio e di testo e qualsiasi
altra risorsa appartenente al suo stesso dominio. Inoltre, lo scambio di script tra due file SWF
dello stesso dominio è sempre consentito, a condizione che entrambi siano stati scritti con
ActionScript 3.0. Lo scambio di script consiste nella capacità di un file SWF di utilizzare
ActionScript per accedere alle proprietà, ai metodi e agli oggetti di un altro file SWF. Lo
scambio di script non è supportato tra file SWF scritti con ActionScript 3.0 e file scritti con
versioni precedenti di ActionScript; tuttavia, questi file sono in grado di comunicare tra loro
mediante la classe LocalConnection. Per ulteriori informazioni, vedere “Scambio di script”
a pagina 832.
Le seguenti regole di sicurezza di base vengono sempre applicate per impostazione predefinita:
■ Le risorse che condividono la stessa funzione di sicurezza sandbox possono sempre
accedere le une alle altre.
■ I file SWF appartenenti a una funzione di sicurezza sandbox remota non possono accedere
a file e dati locali.
Flash Player considera i seguenti domini come domini singoli e imposta per ciascuno di essi
funzioni di sicurezza sandbox specifiche:
■ http://example.com
■ http://www.example.com
■ http://store.example.com
■ https://www.example.com
■ http://192.0.34.166
Impostazioni
amministratore
(istituzione dell’utente)
Impostazioni utente
Impostazioni autore
Ciò significa, ad esempio, che se un amministratore limita l’accesso a una risorsa, nessun altro
stakeholder può ignorare tale restrizione.
I controlli amministratore, utente e sito Web vengono illustrati nelle sezioni che seguono.
Le impostazioni del creatore (sviluppatore) vengono descritte nella parte restante di questo
capitolo.
File mms.cfg
Nei sistemi Mac OS X, il file mms.cfg si trova in /Library/Supporto Applicazioni/
Macromedia/mms.cfg. Nei sistemi Microsoft Windows, tale file si trova nella cartella
Macromedia Flash Player, nella directory di sistema (ad esempio,
C:\windows\system32\macromed\flash\mms.cfg, in un’installazione di Windows XP
predefinita).
All’avvio, Flash Player legge le impostazioni di sicurezza da questo file e le impiega per limitare
le funzionalità.
Il file mms.cfg include impostazioni utilizzate dall’amministratore per eseguire le seguenti
attività:
■ Caricamento dati — Limita la lettura dei file SWF locali, disabilita lo scaricamento e il
caricamento dei file e imposta il limite di memorizzazione per oggetti condivisi persistenti.
■ Controlli per la riservatezza — Disattiva l’accesso a microfono e fotocamera, nega ai file
SWF di riprodurre contenuto senza finestre e impedisce ai file SWF di un dominio che
non corrisponde all’URL visualizzato in una finestra di browser di accedere a oggetti
condivisi persistenti.
■ Aggiornamenti di Flash Player — Imposta l’intervallo di verifica di versioni aggiornate di
Flash Player, specifica l’URL per la ricerca di informazioni sugli aggiornamenti di Flash
Player, imposta l’URL da cui scaricare le versioni aggiornate di Flash Player e disattiva
completamente gli aggiornamenti automatici di Flash Player.
■ Supporto di file legacy — Specifica se collocare file SWF di versioni precedenti nella
sandbox locale affidabile.
■ Sicurezza dei file locali — Specifica se i file locali possono essere collocati nella sandbox
locale affidabile.
■ Modalità a schermo intero — Disabilita la modalità a schermo intero.
I percorsi elencati in un file di configurazione affidabile devono sempre essere percorsi locali o
percorsi di rete SMB. I percorsi HTTP sono ignorati nel file di configurazione affidabile; solo
i file locali possono essere considerati affidabili.
Per evitare conflitti, assegnare a ogni file di configurazione affidabile un nome corrispondente
all’applicazione di installazione e utilizzare l’estensione .cfg.
Controlli utente
Flash Player offre tre diversi meccanismi a livello utente per l’impostazione delle
autorizzazioni: l’interfaccia utente Impostazioni, Gestione impostazioni e la directory User
Flash Player Trust.
Quando un file SWF tenta di accedere a dati da un dominio diverso, Flash Player tenta
automaticamente di caricare un file di criteri dal quel dominio. Se il dominio del file SWF che
tenta di accedere ai dati è compreso nel file dei criteri, i dati sono accessibili automaticamente.
Ogni tag <allow-access-from> dispone dell’attributo opzionale secure che ha come valore
predefinito true. È possibile impostarlo su false se il file di criteri si trova su un server
HTTPS e si desidera consentire ai file SWF di un server non HTTPS di caricare dati dal
server HTTPS.
Utilizzare un file di criteri che non contiene tag <allow-access-from> equivale a non
utilizzare alcun criterio su un server.
Quando i file di criteri sono stati introdotti per la prima volta in Flash Player 6, i file di criteri
socket non erano supportati. Le connessioni ai server socket venivano autorizzate da un file di
criteri contenuto nel percorso predefinito del file di criteri dei domini su un server HTTP
collegato alla porta 80 dello stesso host del server socket. Per consentire la conservazione delle
disposizioni server esistenti, Flash Player 9 supporta ancora tale funzionalità. Tuttavia,
l’impostazione predefinita di Flash Player ora prevede il recupero di un file di criteri socket
sulla stessa porta della connessione socket. Se si desidera utilizzare un file di criteri basato su
HTTP per autorizzare connessioni socket, è necessario richiedere esplicitamente il file di
criteri HTTP mediante un codice simile al seguente:
Security.loadPolicyFile("http://socketServerHost.com/crossdomain.xml")
Inoltre, per autorizzare connessioni socket, il file di criteri HTTP deve provenire unicamente
dallo stesso percorso predefinito del file di criteri dei domini e non da altri percorsi HTTP. Un
file di criteri ottenuto da un server HTTP autorizza implicitamente l’accesso socket a tutte le
porte 1024 e superiori; qualsiasi attributo to-ports presente nel file di criteri HTTP viene
ignorato.
Per ulteriori informazioni sui file di criteri socket, vedere “Connessione a socket”
a pagina 840.
Proprietà Security.sandboxType
Il creatore di un file SWF può utilizzare la proprietà statica di sola lettura
Security.sandboxType per determinare a quale tipo di sandbox Flash Player ha assegnato il
file SWF. La classe Security include costanti che rappresentano possibili valori della proprietà
Security.sandboxType, come indicato di seguito:
■ Security.REMOTE — Il file SWF deriva da un URL Internet e viene gestito tramite regole
sandbox basate sul dominio.
■ Security.LOCAL_WITH_FILE — Questo file SWF è un file locale che non è considerato
affidabile dall’utente e non è stato pubblicato con una designazione di rete. Il file SWF
può leggere le origini dati locali, ma non può comunicare con Internet.
■ Security.LOCAL_WITH_NETWORK — Questo file SWF è un file locale che non è
considerato affidabile dall’utente, ma è stato pubblicato con una designazione di rete.
Il file SWF può comunicare con Internet, ma non può leggere da origini dati locali.
■ Security.LOCAL_TRUSTED — Questo file SWF è un file locale che è stato considerato
affidabile dall’utente tramite Gestione impostazioni o il file di configurazione Flash Player
Trust. Il file SWF può leggere le origini dati locali e comunicare con Internet.
Una pagina HTML può anche usare uno script per generare tag di incorporamento SWF.
È necessario modificare lo script in modo da inserire le impostazioni allowNetworking
corrette. Le pagine HTML generate da Flash e Adobe Flex Builder impiegano la funzione
AC_FL_RunContent() per incorporare riferimenti a file SWF; l’utente deve aggiungere le
impostazioni del parametro allowNetworking come indicato di seguito:
AC_FL_RunContent( ... "allowNetworking", "none", ...)
Una pagina HTML può anche usare uno script per generare tag di incorporamento SWF.
È necessario modificare lo script in modo da inserire le impostazioni allowFullScreen
corrette. Le pagine HTML generate da Flash e Flex Builder impiegano la funzione
AC_FL_RunContent() per incorporare riferimenti a file SWF; l’utente deve aggiungere le
impostazioni del parametro allowFullScreen come indicato di seguito:
AC_FL_RunContent( ... "allowFullScreen", "true", ...)
Il parametro ActionScript che avvia la modalità a schermo intero può essere chiamato solo in
risposta a un evento associato al mouse o alla tastiera. Se viene chiamato in altre situazione,
Flash Player genera un’eccezione.
In modalità a schermo intero, gli utenti non possono immettere testo nei campi di
inserimento testo. Tutti gli input di tastiera e le operazioni di tastiera di ActionScript sono
disabilitate in modalità a schermo intero, a eccezione delle scelte rapide da tastiera (quale il
tasto Esc) che consentono di riportare l’applicazione in modalità normale.
Caricamento di contenuto
Un file SWF può caricare i seguenti tipi di contenuto:
■ File SWF
■ Immagini
■ Audio
■ Video
Solo i file SWF locali sono in grado di caricare file multimediali dal file system locale. E solo i
file SWF nella sandbox locale con file system o nella sandbox locale affidabile possono
accedere ai dati contenuti in tali file caricati.
Esistono altre restrizioni relative all’accesso ai dati dei file multimediali caricati. Per
informazioni dettagliate, vedere “Accesso a file multimediali caricati come dati” a pagina 836.
Si noti, tuttavia, che i file SWF e le immagini caricate in questo modo vengono inseriti nella
sandbox corrispondente alla rispettiva origine.
Quando si carica un file di immagine utilizzando un tag <img> in un campo di testo, l’accesso
ai dati di tale file può essere autorizzato da un file di criteri dei domini. Per verificare la
presenza di un file di criteri, aggiungere l’attributo checkPolicyFile al tag <img>, come nel
codice seguente:
<img src = 'filename.jpg' checkPolicyFile = 'true' id = 'instanceName' >
Quando si carica un file SWF mediante un tag <img> in un campo di testo, è possibile
consentire l’accesso ai dati di tale file SWF chiamando il metodo Security.allowDomain().
Quando si utilizza un tag <img> in un campo di testo per caricare un file esterno (anziché
utilizzare una classe Bitmap incorporata al file SWF), viene automaticamente creato un
oggetto Loader come elemento secondario dell’oggetto TextField e il file esterno viene caricato
nel Loader come se fosse stato caricato in ActionScript mediante l’oggetto Loader. In questo
caso, il metodo getImageReference() restituisce l’oggetto Loader creato automaticamente.
Non è necessaria alcuna verifica di sicurezza per accedere a questo Loader poiché si trova nella
stessa sandbox di sicurezza del codice chiamante.
Scambio di script
Se due file SWF sono stati creati con ActionScript 3.0 e sono gestiti dallo stesso dominio
(ad esempio, l’URL di un file SWF è http://www.example.com/swfA.swf e l’URL dell’altro è
http://www.example.com/swfB.swf ) un file SWF può esaminare e modificare variabili,
oggetti, proprietà e metodi dell’altro e vice versa. Questa operazione è detta scambio di script.
Lo scambio di script non è supportato tra file SWF AVM1 e AVM2. I file SWF AVM1 sono
file creati con ActionScript 1.0 o ActionScript 2.0 (la dicitura AVM1 e AVM2 è riferita ad
ActionScript Virtual Machine). È tuttavia possibile utilizzare la classe LocalConnection per
scambiare dati tra AVM1 e AVM2.
Se due file SWF scritti con ActionScript 3.0 appartengono a domini diversi, ad esempio
http://siteA.com/swfA.swf e http://siteB.com/siteB.swf, per impostazione predefinita Flash
Player non permette a swfA.swf di inviare script a swfB.swf e a swfB.swf di inviare script a
swfA.swf. Il file SWF permette ai file SWF di altri domini di scambiare script tramite la
chiamata alla funzione Security.allowDomain(). La chiamata a
Security.allowDomain("siteA.com") consente a swfB.swf di ricevere script dai file SWF
di siteA.com.
siteA.com / swfA.swf
SWF
myLoader.content.eggCount = 3; 1 carica
myLoader.content.DisplayEggs();
scambio di script
3 2 autorizzazione
Security.allowDomain("siteA.com");
var eggCount:Number;
function DisplayEggs() { ... };
Stage, sicurezza
Alcune proprietà e metodi dell’oggetto Stage sono disponibili a tutti gli oggetti sprite o clip
filmato presenti nell’elenco di visualizzazione.
Tuttavia, l’oggetto Stage presenta un proprio titolare: vale a dire il primo file SWF caricato.
Per impostazione predefinita, le proprietà e i metodi seguenti dell’oggetto Stage sono
disponibili unicamente ai file SWF che si trovano nella stessa sandbox di sicurezza del titolare
dello stage:
Proprietà Metodi
align showDefaultContextMenu addChild()
scaleMode
Perché un file SWF in una sandbox diversa da quella del titolare dello stage possa accedere a
queste proprietà e metodi, il file SWF titolare dello stage deve chiamare il metodo
Security.allowDomain() per consentire l’accesso a domini di una sandbox esterna. Per
ulteriori informazioni, vedere “Controlli creatore (sviluppatore)” a pagina 820.
Per gli eventi che vengono inviati da oggetti diversi da oggetti di visualizzazione, non sono
previste verifiche o altre implicazioni di sicurezza.
Quando si carica l’audio mediante il metodo load() della classe Sound, è possibile specificare
un parametro context, che è un oggetto SoundLoaderContext. Se la proprietà
checkPolicyFile dell’oggetto SoundLoaderContext viene impostata su true, Flash Player
verifica la presenza di un file di criteri validi per domini diversi sul server da cui viene caricato
l’audio. Se esiste un file di criteri dei domini che consente l’accesso al dominio del file SWF da
caricare, il file può accedere alla proprietà id dell’oggetto Sound; in caso contrario, non vi può
accedere. Inoltre, l’impostazione della proprietà checkPolicyFile può attivare il metodo
SoundMixer.computeSpectrum() per i file audio caricati.
È possibile utilizzare il metodo SoundMixer.areSoundsInaccessible() per sapere se una
chiamata al metodo SoundMixer.stopAll() non consente l’interruzione della riproduzione
audio perché la sandbox di uno o più titolari non è accessibile al chiamante.
Connessione a socket
Per impostazione predefinita, l’accesso a socket e socket XML appartenenti a domini differenti
non è consentito. È inoltre disabilitato, per impostazione predefinita, l’accesso a connessioni
socket dello stesso dominio del file SWF su porte inferiori a 1024. Per consentire l’accesso a
tali porte è necessario gestire un file di criteri dei domini da una delle seguenti posizioni:
■ La stessa porta della connessione socket principale
■ Una porta differente
■ Un server HTTP sulla porta 80 nello stesso dominio del server socket
Se si gestisce il file di criteri dei domini dalla stessa porta della connessione socket principale, o
da una porta differente, le porte autorizzate vengono enumerate mediante l’attributo to-
ports nel file di criteri dei domini, come illustrato nell’esempio seguente:
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy
SYSTEM "http://www.adobe.com/xml/dtds/cross-domain-policy.dtd">
<!-- Policy file for xmlsocket://socks.mysite.com -->
<cross-domain-policy>
<allow-access-from domain="*" to-ports="507" />
<allow-access-from domain="*.example.com" to-ports="507,516" />
<allow-access-from domain="*.example.org" to-ports="516-523" />
<allow-access-from domain="adobe.com" to-ports="507,516-523" />
<allow-access-from domain="192.0.34.166" to-ports="*" />
</cross-domain-policy>
Quando il server riceve la stringa, il file di criteri può essere trasmesso. Non è possibile
riutilizzare la stessa connessione per la richiesta di un file di criteri e per la connessione
principale; la connessione deve essere chiusa dopo la trasmissione del file di criteri. In caso
contrario, Flash Player chiude la connessione per la trasmissione del file di criteri prima di
riconnettersi per l’impostazione della connessione principale.
Per ulteriori informazioni, vedere “File dei criteri socket” a pagina 818.
Invio di dati
L’invio di dati si verifica quando il codice ActionScript invia dati da un file SWF a un server o
a una risorsa. L’invio di dati è sempre consentito per file SWF di domini della rete. Un file
SWF locale può inviare dati a indirizzi di rete solo se si trova nella sandbox locale affidabile o
locale con rete. Per ulteriori informazioni, vedere “Funzioni di sicurezza sandbox locali”
a pagina 822.
È possibile utilizzare la funzione flash.net.sendToURL() per inviare dati a un URL.
Vi sono anche altri metodi per inviare richieste a URL. Tra essi vi sono metodi di caricamento,
quali Loader.load() e Sound.load() e metodi di caricamento dati, quali
URLLoader.load() e URLStream.load().
Sui server che richiedono l’autenticazione dell’utente, solo i file SWF in esecuzione in un
browser (ovvero quelli che utilizzano il plug-in per il browser o il controllo ActiveX)
possono fornire una finestra di dialogo per richiedere all’utente di immettere un nome
utente e una password per l’autenticazione, e solo per gli scaricamenti. Flash Player non
consente il caricamento su server che richiedono l’autenticazione utente.
Le operazioni di caricamento e scaricamento non sono consentite se il file SWF che effettua la
chiamata si trova in nella sandbox locale con file system.
Per impostazione predefinita, un file SWF non può avviare un caricamento su o uno
scaricamento da un server diverso dal proprio. Un file SWF può eseguire operazioni di
caricamento su o scaricamento da server differenti, se tale server contiene un file di criteri dei
domini in grado di concedere l’autorizzazione di accesso al dominio del file SWF richiedente.
Impostazione di autorizzazioni
LocalConnection
La classe LocalConnection consente di sviluppare file SWF che inviano istruzioni gli uni agli
altri. Gli oggetti LocalConnection possono comunicare solo tra i file SWF in esecuzione sullo
stesso client, ma possono essere eseguiti in applicazioni diverse (ad esempio, un file SWF in
esecuzione in un browser e un file SWF in esecuzione in un proiettore).
Per ogni comunicazione LocalConnection, esiste un file SWF mittente e un file SWF listener.
Per impostazione predefinita, Flash Player consente comunicazioni LocalConnection tra file
SWF dello stesso dominio. Per file SWF che si trovano in sandbox differenti, il file listener
deve concedere l’autorizzazione al file mittente mediante il metodo
LocalConnection.allowDomain(). La stringa trasmessa come argomento al metodo
LocalConnection.allowDomain() può contenere: nomi di dominio esatti, indirizzi IP e il
carattere jolly *.
N OT A
Un file SWF può utilizzare la proprietà domain della classe LocalConnection per determinare
il proprio dominio.
Oggetti condivisi
Flash Player consente di usare oggetti condivisi, vale a dire oggetti di ActionScript che
persistono al di fuori dei file SWF, sia a livello locale su un file system di un utente o in remoto
su un server RTMP. Gli oggetti condivisi, come altri file multimediali di Flash Player, sono
suddivisi in funzioni di sicurezza sandbox. Tuttavia, il modello di sandbox degli oggetti
condivisi è un po’ differente, in quanto gli oggetti condivisi non sono risorse accessibili da un
dominio a un altro. Al contrario, gli oggetti condivisi vengono sempre recuperati da un
apposito archivio specifico del dominio di ciascun file SWF che chiama i metodi della classe
SharedObject. Generalmente, l’archivio degli oggetti condivisi è ancora più particolare di un
dominio di file SWF: per impostazione predefinita, ogni file SWF impiega un archivio di
oggetti condivisi particolare in base al proprio URL di origine.
Un file SWF può utilizzare il parametro localPath dei metodi SharedObject.getLocal() e
SharedObject.getRemote() per usare un archivio di oggetti condivisi associato con solo una
parte del proprio URL. In questo modo, il file SWF può consentire la condivisione con altri
file SWF di altri URL. Anche se si trasmette '/' come parametro localPath, ciò specifica
ancora un archivio di oggetti condivisi particolare del dominio.
La scelta di un archivio di oggetti condivisi si basa sull’URL di origine del file SWF. Ciò si
verifica anche nelle due situazioni in cui un file SWF non ha origine da un semplice URL, vale
a dire nei casi di caricamento mediante importazione e di caricamento dinamico. Il
caricamento mediante importazione avviene quando un file SWF viene caricato con la
proprietà LoaderContext.securityDomain impostata su
SecurityDomain.currentDomain. In questa situazione, il file SWF caricato presenta uno
pseudo URL che inizia con il dominio del file SWF caricante, quindi specifica l’effettivo URL
di origine. Il caricamento dinamico si riferisce al caricamento di un file SWF mediante il
metodo Loader.loadBytes(). In questa situazione, il file SWF caricato avrà uno pseudo
URL che inizia con l’intero URL del file SWF che esegue il caricamento, seguito da un ID di
numero intero. In entrambi i casi, è possibile esaminare lo pseudo URL del file SWF
utilizzando la proprietà LoaderInfo.url. Lo pseudo URL viene trattato esattamente come
un vero URL allo scopo di scegliere un archivio di oggetti condivisi. È possibile specificare un
parametro localPath di oggetto condiviso che impiega in parte o per intero lo pseudo URL.
849
addEventListener(), metodo 167, 342, 356 area di validità globale 143
additivi, operatori 121 argomenti, passati mediante un valore
addizione (+), operatore 223 o un riferimento 137
addListener(), metodo 342 arguments, oggetto 136, 139, 141
allowDomain(), metodo arguments.callee, proprietà 139
audio 839 arguments.caller, proprietà 140
contesto di caricamento 452 arguments.length, proprietà 139
funzione di costruzione 843 array
img, tag 831 array nidificati e metodo join() 251
informazioni sullo scambio di script 832 associativi 251
LocalConnection, classe 703 attività comuni 241
allowFullScreen, attributo 827 chiave e coppie di valori 252
allowInsecureDomain(), metodo 703 chiavi oggetto 253
allowNetworking, tag 825 clonazione 258
AllowScriptAccess, parametro 845 copia profonda 258
alternative nelle espressioni regolari 318 copia superficiale 258
altoparlanti e microfoni 659 creazione 226, 243
ambiente del sistema client delete, operatore 246
informazioni 739 dimensione massima 242
operazioni comuni 740 esempi 265
ambiente lessicale 144 funzione di costruzione 243
animazione 447 indicizzati 242
annotazioni di tipo 88, 94 informazioni 239
API esterna inserimento elementi 244
concetti e termini 779 iterazione 254
esempio 789 lunghezza 246
informazioni 778 multidimensionale 256
operazioni comuni 778 ordinamento 246
vantaggi 781 query 250
XML, formato 787 rimozione elementi 245
application/x-www-form-urlencoded 691 supercostruttore 261
ApplicationDomain, classe 453, 745, 830 termini 241
applicazione dell'effetto maschera ai canali alfa 446 tipizzati, non supportati 243
applicazioni per podcast uso di array associativi e indicizzati 257
creazione 662 valori letterali di array 112, 244
estensione 670 array con indice 242
applicazioni, decisioni per lo sviluppo 51 array non ordinati 251
apply(), metodo 261 array tipizzati 243
Appunti Array, classe
salvataggio di testo 743 algoritmo della funzione di costruzione 261
sicurezza 848 concat(), metodo 250
architettura di visualizzazione 395, 482 estensione 259
archiviazione dei dati 711 join(), metodo 250
archiviazione locale 711 length, proprietà 246, 253
area di validità pop(), metodo 245
funzioni 135, 143 push(), metodo 244, 262
globale 143 reverse(), metodo 246
livello di blocco 90 shift(), metodo 245
variabili 89 slice(), metodo 250
area di validità a livello di blocco 90 sort(), metodo 246
W
while, ciclo 129
Wiki, esempio di parser 328
willTrigger(), metodo 357
WordSearch, esempio 682
wrapper, oggetti 93
X
x, flag (nelle espressioni regolari) 322
XML
accesso agli attributi 384
ActionScript per 370
caricamento dati 379, 390
cicli for 374, 386
commenti 374, 375