Come creare un evento MouseEvent.CLICK personalizzato in AS3 (passare i parametri alla funzione)?
-
06-07-2019 - |
Domanda
Questa domanda non riguarda solo il tipo di evento MouseEvent.CLICK ma tutti i tipi di eventi già esistenti in AS3. Ho letto molto sugli eventi personalizzati ma fino ad ora non sono riuscito a capire come fare quello che voglio fare. Proverò a spiegare, spero che tu capisca:
Ecco un esempio della mia situazione:
for(var i:Number; i < 10; i++){
var someVar = i;
myClips[i].addEventListener(MouseEvent.CLICK, doSomething);
}
function doSomething(e:MouseEvent){ /* */ }
Ma voglio essere in grado di passare someVar come parametro a doSomething . Quindi ho provato questo:
for(var i:Number; i < 10; i++){
var someVar = i;
myClips[i].addEventListener(MouseEvent.CLICK, function(){
doSomething(someVar);
});
}
function doSomething(index){ trace(index); }
Questo tipo di lavori funziona ma non come mi aspetto. A causa della chiusura delle funzioni, quando gli eventi MouseEvent.CLICK vengono effettivamente attivati, il ciclo for è già terminato e someVar contiene l'ultimo valore, il numero 9 nell'esempio. Quindi ogni clic in ogni clip filmato chiamerà doSomething passando 9 come parametro. E non è quello che voglio.
Ho pensato che la creazione di un evento personalizzato avrebbe dovuto funzionare, ma poi non sono riuscito a trovare un modo per generare un evento personalizzato quando l'evento MouseEvent.CLICK viene generato e passare il parametro ad esso. Ora non so se è la risposta giusta.
Cosa devo fare e come?
Soluzione
Senza sapere di più sulla tua applicazione, sembra più che dovresti usare la destinazione per passare i parametri o estendere MouseEvent. Il primo sarebbe tuttavia più in linea con la pratica comune. Ad esempio, se hai esposto una proprietà pubblica intera sul tuo " clip " oggetto (qualunque esso sia):
public class MyClip
{
public var myPublicProperty:int;
public function MyClip() { //... }
}
for (var i:int = 0; i < 10; i++)
{
myClips[i].myPublicProperty = i;
myClips[i].addEventListener(MouseEvent.CLICK, doSomething);
}
... e quindi, nel tuo listener di eventi, potresti recuperare quella proprietà usando la proprietà target o currentTarget dell'evento (probabilmente currentTarget, nel tuo caso):
function doSomething(event:MouseEvent):void
{
trace(event.currentTarget.myPublicProperty.toString());
}
Dovrebbe farlo! Buona fortuna.
Altri suggerimenti
Devi davvero estendere la classe dell'evento per creare il tuo evento con parametri extra. Inserire le funzioni all'interno di addEventListener (funzioni anonime) è una ricetta per le perdite di memoria, il che non va bene. Dai un'occhiata a quanto segue.
import flash.events.Event;
//custom event class to enable the passing of strings along with the actual event
public class TestEvent extends Event
{
public static const TYPE1 :String = "type1";
public static const TYPE2 :String = "type2";
public static const TYPE3 :String = "type3";
public var parameterText:String;
public function TestEvent (type:String, searchText:String)
{
this.parameterText = searchText;
super(type);
}
}
quando crei un nuovo evento come
dispatchEvent(new TestEvent(TestEvent.TYPE1, 'thisIsTheParameterText'))" ;
puoi quindi ascoltare l'evento come questo
someComponent.addEventListener(TestEvent.TYPE1, listenerFunction, true , 0, true);
e all'interno della funzione 'listenerFunction' event.parameterText conterrà il tuo parametro.
quindi, all'interno del componente myClips, attiverai l'evento personalizzato e ascolterai l'evento e non l'evento Click.
private function myCallbackFunction(e:Event, parameter:String):void
{
//voila, here's your parameter
}
private function addArguments(method:Function, additionalArguments:Array):Function
{
return function(event:Event):void {method.apply(null, [event].concat(additionalArguments));}
}
var parameter:String = "A sentence I want to pass along";
movieClip.addEventListener(Event.COMPLETE, addArguments(myCallbackFunction, [parameter] ) );
Approfitta della costruzione della funzione dinamica in AS3.
È possibile ottenere questo risultato estraendo il gestore da una funzione che fornisce la chiusura variabile, in questo modo:
for (var i=0; i<5; i++) {
myClips[i].addEventListener( MouseEvent.CLICK, getHandler(i) );
}
function getHandler(i) {
return function( e:MouseEvent ) {
test(i);
}
}
function test( j ) {
trace("foo "+j);
}
Inoltre, per il motivo per cui questo crea una nuova chiusura, potresti voler controllare la spiegazione nella risposta accettata a questa domanda simile .
Grazie mille per questi utili suggerimenti, questa tecnica è meglio capire della spiegazione delle classi.
per me ho appena iniziato un nuovo algoritmo di codice usando questa tecnica per risolvere la relazione di collegamento tra array di timer e array di finestre e aggiornare lo stato modificando frequentemente il testo al loro interno, passando ID con eventi timer.
in questo modo:
var view:Object=[];
for(var i:uint=0;i<Camera.names.length;i++){
view[i]=getChildByName("Cam"+i);
//_________ Add Text _________
var tf:TextField = new TextField();
tf.autoSize = TextFieldAutoSize.LEFT;
tf.textColor=0xffffff;
view[i].tf=view[i].addChild(tf);
//_________ Add Timer _________
var t:Timer = new Timer(1000);
view[i].timer=t;
view[i].timer.start();
view[i].timer.addEventListener(TimerEvent.TIMER, addArg(i));
}
function addArg(adi:uint):Function {
return function(event:TimerEvent):void {
updatecamstatus(adi);
}
}
function updatecamstatus(vH:uint):void {
with (view[vH]){
tf.text="Cam" + vH + "\n";
tf.appendText("activityLevel: " + videosource.activityLevel + "\n");
tf.appendText("motionLevel: " + videosource.motionLevel + "\n");
}
}
Vedo che il tuo obiettivo principale non è effettivamente quello di creare un MouseEvent.CLICK personalizzato, ma di passare un parametro alla funzione. Non è necessario creare o estendere complicatamente nulla. C'è un modo semplice e senza problemi di chiusura per farlo.
Rendi la tua funzione così:
function doSomething(index:Number):Function {
return function(e:MouseEvent):void {
// Use "e" and "index" here. They'll be unique for each addEventListener()
trace(index);
}
}
Questa tecnica può essere correlata a qualsiasi tipo di evento AS3 su cui è possibile utilizzare addEventListener.
E ora puoi aggiungerlo in questo modo:
var functionsDoSomething:Object;
for (var i:Number = 0; i < 10; i++) {
var someVar:Number = i;
functionsDoSomething[i] = doSomething(someVar);
myClips[i].addEventListener(MouseEvent.CLICK, functionsDoSomething[i]);
}
doSomething (someVar)
può essere utilizzato direttamente su addEventListener ()
, ma è meglio tenerlo in una variabile perché potrai rimuoverlo in seguito lo stesso modo in cui l'hai aggiunto:
for (i = 0; i < 10; i++) {
myClips[i].removeEventListener(MouseEvent.CLICK, functionsDoSomething[i]);
}
Il e.currentTarget.someCustomProperty
comunemente usato funziona per oggetti dinamici (ad es. MovieClip), ma ti deluderà in qualsiasi altra cosa (ad esempio Sprite), costringendoti a costruire un intero oggetto esteso personalizzato / evento per ogni tipo.
Questa soluzione si occupa di ogni "quotabile" " oggetto ed evento. E questa risposta contiene più dettagli ed esempi.