views:

2247

answers:

2

Hi, I have many buttons in Main.mxml. I'm trying to move the button functionality into a Class and have Event Listeners inside the class respond to Click and call other functions. I have written:

Main.mxml

<mx:Button x="23.5" y="10" label="checker" click="{goListen()}" />
<mx:Button id="btnT1" x="252.5" y="10" label="t1" />
<mx:Button id="btnT2" x="309" y="10" label="t2"/>
<mx:Button id="btnT3" x="366" y="10" label="t3"/>

Main.as

private function goListen():void
 {
  var t:ButtonListener = new ButtonListener(btnT1, btnT2, btnT3);
 }

ButtonListener.mxml

package com.util

{ import flash.events.EventDispatcher; import flash.events.MouseEvent;

import mx.controls.Alert;
import mx.controls.Button;

public final class ButtonListener extends EventDispatcher
{
 private var __btnArray:Array;

 public function ButtonListener(...btnList)
 {
  __btnArray = new Array();

  for each (var item:Button in btnList)
  {
   __btnArray.push(item);
  }

  buildListeners();
 }

 private function buildListeners():void
 {
  for each (var item:Button in __btnArray)
  {
   item.addEventListener(MouseEvent.CLICK, traceMe, false, 0, true);
  }
 }

 private function traceMe(event:MouseEvent):void
 {
  trace(event.target.label + " was clicked");
 }
}

}

so when I debug, I see the array filling up with the buttons, but the traceMe() function won't work. Not sure how I can get this to work. Or do I just have to have 30 event listeners and corresponding functions in the main class.

+1  A: 

Since the click event of Button bubbles, you can just listen for a click event on the main application file and delegate to a handler function in a class.

Or you can call the handler directly on the click of your button.

private var controller:ButtonListener = new ButtonListener();

<mx:Button id="btnT1" x="252.5" y="10" label="t1" click="controller.handleClick(event)"/>
Christophe Herreman
+1  A: 

It looks like you have two different options or problems. If you change the last parameter in:

item.addEventListener(MouseEvent.CLICK, traceMe, false, 0, true);

to false, then everything should work because your event listener will stick around to handle the mouse clicks. Of courses, this means that if you click on your "checker" button a second time, you'll then have two sets of listeners responding to mouse clicks of buttons one, two, and three.

So, it's likely that the real solution you're interested in is leaving the line quoted above the same and instead changing the following line:

var t:ButtonListener = new ButtonListener(btnT1, btnT2, btnT3);

If you change the above line to store your button listener as a part of your class it will be available to respond to the mouse clicks, rather than having been garbage collected:

_buttonListener = new ButtonListener(btnT1, btnT2, btnT3);

That, of course, assumes that you have defined _buttonListener within an mx:script block:

<mx:Script><![CDATA[
    var _buttonListener:ButtonListener;
 ]]></mx:Script>

EDIT per comment:

In the code provided, t, the ButtonListener, goes out of scope. When it does, it is garbage collected unless you use strong references, which you do not per the last parameter in your addEventListener call.

Thus, make the button listener a member of the main class:

Main.mxml would then read:

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
    <mx:Button x="23.5" y="10" label="checker" click="{goListen()}" />
    <mx:Button id="btnT1" x="252.5" y="10" label="t1" />
    <mx:Button id="btnT2" x="309" y="10" label="t2"/>
    <mx:Button id="btnT3" x="366" y="10" label="t3"/>
    <mx:Script>
        <![CDATA[
            private var _buttonListener:ButtonListener;

            private function goListen():void
            {                
                _buttonListener = new ButtonListener(btnT1, btnT2, btnT3); 
            }
        ]]>
    </mx:Script>
</mx:Application>

Since the event listener will no longer go out of scope, the weak references used by the event listeners will work as expected, being garbage collected when __buttonListener goes out of scope.

Kaleb Pederson
Kaleb, the first solution you posted works because I was using the checker button as a test to instantiate the ButtonListener class. I will however be instantiating it when app loads. I can't get garbage collect the event listeners anyway since I require all of the buttons to play throughout all of the movie. However, I do not understand your 2nd solution. Would you be so kind as to elaborate on it?
Tomaszewski