如何在Flex / ActionScript中将参数传递给事件侦听器函数?

24

在使用 Sqlite 时,如果您同时尝试执行函数,则会引发错误。我只是想编写一个函数来检查它是否正在执行,如果是,则再等待 10 毫秒并重试。如果不需要将任何参数传递给该函数,则此函数可以正常工作,但是我不知道如何将变量传回正在执行的函数中。

我的意图是:

timer.addEventListener(TimerEvent.TIMER, saveChat(username, chatBoxText));

但是它只允许我做:

timer.addEventListener(TimerEvent.TIMER, saveChat);

我遇到了这个编译错误:

1067: 将类型为 void 的值隐式强制转换为不相关的类型 Function

我该如何使代码能通过这个限制?

以下是我的代码:

public function saveChat(username:String, chatBoxText:String, e:TimerEvent=null):void
{
    var timer:Timer = new Timer(10, 1);
    timer.addEventListener(TimerEvent.TIMER, saveChat);

    if(!saveChatSql.executing)
    {
        saveChatSql.text = "UPDATE active_chats SET convo = '"+chatBoxText+"' WHERE username = '"+username+"';";
        saveChatSql.execute();
    }
    else timer.start();
}
5个回答

27

一个被监听器调用的函数只能有一个参数,即触发它的事件。

listener:Function — 处理事件的监听器函数。 此函数必须接受一个Event对象作为其唯一参数,并且必须返回void,就像此示例所示:

function(evt:Event):void

来源

您可以通过使事件调用另一个带有所需参数的函数来绕过这个限制:

timer.addEventListener(TimerEvent.TIMER, _saveChat);
function _saveChat(e:TimerEvent):void
{
    saveChat(arg, arg, arg);
}

function saveChat(arg1:type, arg2:type, arg3:type):void
{
    // Your logic.
}

你可以创建一个继承自flash.events.Event的自定义事件类,并在其中创建需要的属性。

package
{
    import flash.events.Event;

    public class CustomEvent extends Event
    {
        // Your custom event 'types'.
        public static const SAVE_CHAT:String = "saveChat";

        // Your custom properties.
        public var username:String;
        public var chatBoxText:String;

        // Constructor.
        public function CustomEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false):void
        {
            super(type, bubbles, cancelable);
        }
    }
}

接下来,您可以使用定义的属性来分派它:

timer.addEventListener(TimerEvent.TIMER, _saveChat);
function _saveChat(e:TimerEvent):void
{
    var evt:CustomEvent = new CustomEvent(CustomEvent.SAVE_CHAT);

    evt.username = "Marty";
    evt.chatBoxText = "Custom events are easy.";

    dispatchEvent(evt);
}

并监听它:

addEventListener(CustomEvent.SAVE_CHAT, saveChat);
function saveChat(e:CustomEvent):void
{
    trace(e.username + ": " + e.chatBoxText);
    // Output: Marty: Custom events are easy.
}

11

实际上,你可以通过使用Actionscript的动态函数构造向事件侦听器传递额外的参数,而无需创建自定义事件。

private function addArguments(method:Function, additionalArguments:Array):Function
{
  return function(event:Event):void {method.apply(null, [event].concat(additionalArguments));}
}

在设置 Alert 窗口的 closeHandler 时,我们调用 addArguments() 方法并传入一个包含所有要传递给 closeHandler 的参数的数组。addHandler() 方法将返回一个函数,该函数将在包括参数的情况下调用 Alert 窗口关闭时。

protected function btnOK_clickHandler(event:MouseEvent):void
{
  Alert.show("Would you like to reverse the text you just entered?", "", Alert.YES | Alert.NO, null, addArguments(alertCloseHandler, [txtInput.text]), null, Alert.YES);
  txtInput.text = "";
}

10

1067:将类型为void的值隐式强制转换为不相关的类型Function

请注意您收到的错误:它说一个Function是一种类型,而addEventListener()需要它。尽管您的监听器返回void,但它仍然是一个Function!那么,返回监听器怎么样?

timer.addEventListener(TimerEvent.TIMER, saveChat(username, chatBoxText));
function saveChat(username:String, chatBoxText:String):Function {
  return function(e:TimerEvent):void {
    // Do everything that uses "e", "chatBoxText" and "username" here!
  };
}

就像这样。它适用于任何类型的事件。而且没有闭包问题。

关于removeEventListener()的注意事项:

不要尝试这样做:timer.removeEventListener(TimerEvent.TIMER, saveChat(username, chatBoxText))。它无法识别您的函数,因为每次使用saveChat()时都会向其传递一个新的函数。相反,将其引用提取到一个变量中即可:

var functionSaveChat:Function = saveChat(username, chatBoxText);
timer.addEventListener(TimerEvent.TIMER, functionSaveChat);
//trace(timer.hasEventListener(TimerEvent.TIMER));
timer.removeEventListener(TimerEvent.TIMER, functionSaveChat);
//trace(timer.hasEventListener(TimerEvent.TIMER));

哇,这真的很有帮助。谢谢!我从来没有看到过这种可能性的评论。使用它是否有任何缺点?也许会有一些内存泄漏或类似的问题吗? - OMA
@OMA 我已经用这个工具好几年了,如果你想确认一下,可以使用内存分析器进行测试。 - user1837285
非常好,谢谢。在我的情况下,我使用event.currentTarget.removeEventListener(MyListener, arguments['callee']);从函数内部删除侦听器,而不是像您建议的那样将函数的引用保存在变量中。 - OMA
在我的情况下,我会在你们两种方式之间切换。主要是使用arguments.callee更简单。但是当我无法从自身中删除监听器时,我就会使用变量中的引用。两种方法都很好。 - user1870316

1
在调用saveChat(arg, arg, arg)之前,这不适合我,我需要传递一些在这个方法中没有的参数,但我有另一个解决方案。
我总是使用额外的方法passParameters来添加新的参数:
public function passParameters(method:Function,additionalArguments:Array):Function
{return function(event:Event):void{
    method.apply(null, [event].concat(additionalArguments));}
}

这里是解释 - 它很简单并且总是有效的 http://sinfinity.pl/blog/2012/03/28/adding-parameters-to-event-listener-in-flex-air-as3/


1
你可以尝试这个:
var timerHandler:Function = function (event:TimerEvent):void
{
   saveChat(username,chatBoxText,event);
}

timer.addEventListener(TimerEvent.TIMER, timerHandler);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接