Как создать собственное событие MouseEvent.CLICK в AS3 (передать параметры в функцию)? - PullRequest
7 голосов
/ 09 января 2009

Этот вопрос относится не только к типу событий MouseEvent.CLICK, но и ко всем типам событий, которые уже существуют в AS3. Я много читал о пользовательских событиях, но до сих пор не мог понять, как делать то, что я хочу делать. Я попытаюсь объяснить, я надеюсь, вы понимаете:

Вот иллюстрация моей ситуации:

for(var i:Number; i < 10; i++){
    var someVar = i;
     myClips[i].addEventListener(MouseEvent.CLICK, doSomething);
}

function doSomething(e:MouseEvent){ /* */ }

Но я хочу иметь возможность передать someVar в качестве параметра doSomething . Итак, я попробовал это:

for(var i:Number; i < 10; i++){

    var someVar = i;
    myClips[i].addEventListener(MouseEvent.CLICK, function(){
        doSomething(someVar);
    });
}

function doSomething(index){ trace(index); }

Такого рода работы, но не так, как я ожидаю. Из-за замыканий функций, когда события MouseEvent.CLICK фактически запускаются, цикл for уже завершен, а someVar содержит последнее значение, число 9 в примере. Поэтому каждый клик в каждом мувиклипе будет вызывать doSomething , передавая 9 в качестве параметра. И это не то, что я хочу.

Я думал, что создание пользовательского события должно сработать, но тогда я не смог найти способ вызвать пользовательское событие, когда событие MouseEvent.CLICK сработало, и передать ему параметр. Теперь я не знаю, правильный ли это ответ.

Что мне делать и как?

Ответы [ 6 ]

7 голосов
/ 09 января 2009

Вам действительно нужно расширить класс событий, чтобы создать собственное событие с дополнительными параметрами. Размещение функций внутри addEventListener (анонимные функции) - это рецепт утечек памяти, что не очень хорошо. Посмотрите на следующее.

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);
    }

}

при создании нового события, например

dispatchEvent(new TestEvent(TestEvent.TYPE1, 'thisIsTheParameterText'))" ;

затем вы можете прослушать это событие, как это

someComponent.addEventListener(TestEvent.TYPE1, listenerFunction, true , 0, true);

и внутри функции 'listenerFunction' event.parameterText будет содержать ваш параметр.

поэтому внутри вашего компонента myClips вы можете запустить пользовательское событие и прослушать это событие, а не событие Click.

6 голосов
/ 09 января 2009

Не зная больше о вашем приложении, похоже, вам следует использовать цель для передачи параметров или расширить MouseEvent. Первый будет больше соответствовать обычной практике. Например, если вы выставили целочисленное общедоступное свойство для вашего объекта «clip» (что бы это ни было):

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);
}

... и затем в своем прослушивателе событий вы можете получить это свойство, используя свойство события target или currentTarget (возможно, currentTarget в вашем случае):

function doSomething(event:MouseEvent):void
{
   trace(event.currentTarget.myPublicProperty.toString());
}

Это должно сделать это! Удачи.

3 голосов
/ 03 января 2011
    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] ) );

Воспользуйтесь преимуществами построения динамических функций в AS3.

2 голосов
/ 09 января 2009

Вы можете сделать это, вытащив свой обработчик из функции, которая дает закрытие переменной, например:

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);
}

Также, что касается того, почему это создает новое закрытие, вы можете проверить объяснение в принятом ответе на этот похожий вопрос .

1 голос
/ 05 декабря 2012

Я вижу, что ваша главная цель на самом деле не создать пользовательский MouseEvent.CLICK, а передать параметр в функцию. Вам не нужно ничего сложно создавать или расширять. Есть простой и безотказный способ сделать это.

Просто сделайте свою функцию такой:

function doSomething(index:Number):Function {
  return function(e:MouseEvent):void {
    // Use "e" and "index" here. They'll be unique for each addEventListener()
    trace(index);
  }
}

Этот метод может относиться к любому типу событий AS3, для которого вы можете использовать addEventListener.

А теперь вы можете добавить это так:

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) может использоваться непосредственно на addEventListener(), но лучше хранить его в переменной, потому что вы сможете удалить его позже так же, как вы его добавили:

for (i = 0; i < 10; i++) {
  myClips[i].removeEventListener(MouseEvent.CLICK, functionsDoSomething[i]);
}

Обычно используемый e.currentTarget.someCustomProperty работает для динамических объектов (например, MovieClip), но подведет вас к чему-либо еще (например, к Sprite), заставляя вас создавать целый пользовательский расширенный объект / событие для каждого типа.

Это решение имеет дело с каждым «слушаемым» объектом и событием. И этот ответ содержит больше деталей и примеров.

1 голос
/ 06 апреля 2011

Большое спасибо за полезные советы, эту технику лучше понять, чем объяснение классов.

для меня я только что начал новый алгоритм кода, используя эту технику, чтобы решить связь между массивом таймеров и массивом областей просмотра и обновлять статус, часто меняя текст внутри них, передавая идентификаторы с событиями таймеров.

как это:

    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"); 
   }
}
...