Estendere il componente ComboBox per caricare dati XML (AS 3.0 – Flash CS3/4)
Problema: popolare due o più ComboBox con contenuti acquisiti da diversi file XML.
Soluzione: estendere la classe ComboBox affinché abbia un nuovo metodo pubblico loadData(xmlPath:String) che accetta come parametro il link del file XML da caricare e incorpora al suo interno tutte le nuove funzionalità per il recupero e la visualizzazione dei dati.
Vantaggi: il principale vantaggio nell’utilizzo di questa tecnica è quello di creare un componente facilmente riutilizzabile che incapsulerà al suo interno tutte le nuove funzionalità, evitando la riscrittura dell’intera procedura ogni qualvolta si riproponga una esigenza analoga.
Il secondo vantaggio derivato da questo approccio è quello di mantenere il codice dell’applicazione pulito e ordinato. Il suo utilizzo all’interno di un progetto, infatti, richiederà pochissime righe di codice e risulterà davvero semplice da usare anche dagli sviluppatori meno esperti (pensiamo ad un progetto affrontato in team in cui i senior sviluppano i componenti e le parti complesse, mentre i junior li utilizzano semplicemente)
Di seguito l’output finale con i due combobox e le strutture XML da cui acquisiremo i dati:
Codice per l’utilizzo del nuovo componente:
Il FILE .FLA PRINCIPALE
Creiamo un nuovo file .fla, assegnando un nome a piacere, e trasciniamo sullo stage un componente Combobox (dal pannello Components -> User Interface) a cui assegneremo come nome istanza ‘countryCmb’.
Posizioniamo poi il seguente codice nel primo frame (o se preferite in una document class abbinata al .fla):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // ComboBox già presente sullo Stage countryCmb.loadData = "xml/countries.xml"; countryCmb.addEventListener(Event.CHANGE, changeCmb); // Nuovo ComboBox istanziato dinamicamente var namesCmb:ComboBoxXML = new ComboBoxXML(); namesCmb.loadData = "xml/names.xml"; namesCmb.addEventListener(Event.CHANGE, changeCmb); namesCmb.x = 200; namesCmb.y = 50; addChild(namesCmb) // Output dell’elemento selezionato da entrambi i combobox function changeCmb(e:Event):void { trace("Selected Item: ", e.currentTarget.selectedItem.label + "( " + e.currentTarget.selectedItem.data + " ) " ); } |
Dal codice si evince che il nostro componente dovrà chiamarsi ComboBoxXML e che integrerà le seguenti funzionalità:
1) un metodo setter loadData() che accetterà come parametro il link del file xml da caricare
2) dispatch dell’evento CHANGE invocato alla selezione di un elemento del combobox
Mentre per il secondo punto non è necessaria alcuna operazione, dato che estendiamo la classe ComboBox ed ereditiamo quindi tale comportamento, per il primo punto sarà necessario creare tre classi:
a) ComboBoxXML.as che estende materialmente la classe ComboBox e integra il metodo pubblico loadData(xmlPath:String)
b) XmlLoader.as che gestisce il caricamento del file XML ed effettua i dispatch alla classe precedente degli eventi relativi al caricamento dati e ad eventuali errori
c) XmlEvent.as che estende la classe Event per la creazione di un custom event (evento personalizzato) per la gestione degli eventi relativi al caricamento dell’XML citati nel punto b)
ComboBoxXML.as: estendiamo la classe ComboBox
Creiamo un nuovo file chiamato ComboBoxXML.as che per semplicità posizioniamo nella stessa cartella del file .fla.
NOTA: per un ordinamento e gestione migliore dei files sarebbe più corretto posizionare le classi in diverse sotto-cartelle, creando a tutti gli effetti una suddivisione in package. Tuttavia, per rendere più semplice il tutorial posizioneremo tutte le classi nella root.
Innanzitutto importiamo due classi:
1 2 | import fl.data.DataProvider; import fl.controls.ComboBox; |
La prima classe ci sarà utile per il popolamento del ComboBox al termine del caricamento dei dati, mentre la seconda è necessaria per estendere e utilizzare le funzionalità della classe ComboBox.
Utilizziamo quindi la keyword extends nella dichiarazione per fare in modo che la nostra classe erediti tutti i comportamenti della classe originale.
Creiamo poi il metodo setter loadData (utilizzando la parola chiave set), il cui unico parametro sarà rappresentato dal link al file XML da caricare.
All’interno di questo metodo istanziamo una nuova classe, che scriveremo nel paragrafo successivo, per la gestione e il caricamento dei dati e che effettuerà il dispatch di due eventi: COMPLETE e IO_ERROR, rispettivamente a caricamento dati avvenuto e in caso di link errato.
A caricamento dati avvenuto, verrà invocato il metodo onLoadXml() e popoleremo quindi il nostro combobox con i dati acquisiti dal file XML utilizzando la classe DataProvider.
ComboBoxXML.as:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | package { import fl.data.DataProvider; import fl.controls.ComboBox; public class ComboBoxXML extends ComboBox { private var xml:XML ; // Constructor public function ComboBoxXML() {} /** * LOAD XML DATA * */ public function set loadData(xmlPath:String):void { var loadXml:XmlLoader = new XmlLoader(xmlPath) loadXml.addEventListener(XmlEvent.COMPLETE, onLoadXml) loadXml.addEventListener(XmlEvent.IO_ERROR, ioError) } /** * LOAD XML COMPLETED * */ private function onLoadXml(e:XmlEvent):void { xml = e.xmlData; this.dataProvider = new DataProvider(xml); } /** * LOAD XML FAILED: IO ERROR * */ private function ioError(e:XmlEvent):void { trace("IOERror:: " + e) } } } |
Riapriamo il nostro file .fla, visualizziamo la libreria(F11), clicchiamo con il pulsante destro del mouse sul nostro componente Combobox e apriamo il menu LINKAGE.
Nel pannello Properties specificheremo la proprietà Class inserendo il nome della nostra nuova classe: ComboBoxXML.
NOTA: Se avessimo posizionato la classe in una sotto cartella avremmo dovuto inserire il percorso completo del package, ad esempio it.actionscript.esempio.ComboBoxXML
Così facendo, associamo la nostra nuova classe al ComboBox presente in libreria, in modo tale che il componente posizionato sullo stage non sia abbinato alla classe ComboBox standard di Flash ma faccia invece riferimento alla nuova classe.
Questo passaggio non sarebbe necessario se il componente fosse istanziato solo dinamicamente con il codice visto in precedenza:
1 | var namesCmb:ComboBoxXML = new ComboBoxXML(); |
XmlLoader.as: caricamento dati da file XML
Questa semplice classe si occuperà di caricare i dati dal file xml e di restituirli alla nostra classe ComboBoxXML sfruttando la tecnica del dispatch.
La classe XmlLoader gestirà infatti i due eventi che abbiamo sopra menzionato (COMPLETE e IO_ERROR) e si occuperà proprio di avvertire (dispatch) la nostra classe principale ogni qualvolta si verificherà una delle due circostanze. Nel caso di caricamento avvenuto sarà inoltre necessario passare come parametro il contenuto XML, affinché la classe ComboBoxXML possa popolare il componente con i dati acquisiti.
Per effettuare questi dispatch purtroppo non potremo usare la classe Event di Flash, perché non gestisce il passaggio di parametri, e dovremo quindi necessariamente estenderla creando un evento personalizzato, XmlEvent, che a tutti gli effetti rappresenterà una nuova tipologia di evento.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | package { import flash.events.* import flash.net.* import flash.display.* public class XmlLoader extends Sprite { private var myXML:XML ; private var myXMLURL:URLRequest; private var myLoader:URLLoader; // Constructor public function XmlLoader(url:String) { myXML = new XML(); myXMLURL = new URLRequest(url); myLoader = new URLLoader(myXMLURL); myLoader.addEventListener("complete", xmlLoaded); myLoader.addEventListener(IOErrorEvent.IO_ERROR, ioError); } // XML Load Completed private function xmlLoaded(event:Event):void{ myXML = XML(myLoader.data); dispatchData(myXML); } // XML Load Failed (wrong url) private function ioError(event:IOErrorEvent):void { // Dispatch Custom XML Event 'ioError' var o:XmlEvent=new XmlEvent("ioError", myXML); dispatchEvent(o); } // Dispatch XML Data private function dispatchData(myXML:XML):void { // Dispatch Custom XML Event 'oncomplete' var o:XmlEvent=new XmlEvent("oncomplete", myXML); dispatchEvent(o); } } } |
XmlEvent.as: creazione di un Custom Event
Per creare quindi l’evento personalizzato sono necessari alcuni passaggi abbastanza standard nella creazione di un CustomEvent:
1) Creare una nuova classe che estende la classe Event
2) Definire le costanti dell’evento
3) Definire le proprietà da dispatchare
4) Modificare il costruttore affinché invochi la superclass e inizializzi le proprietà
5) Fare un override del metodo clone()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | // Custom XML Event Class package { import flash.events.Event; public class XmlEvent extends Event { public static const COMPLETE:String = "oncomplete"; public static const IO_ERROR:String = "ioError"; public var xmlData:XML; public function XmlEvent(type:String, data:XML) { super(type); this.xmlData = data; } override public function clone():Event { return new XmlEvent(type, xmlData); } } } |














Leave your response!