Can I pass a button into its own MouseEvent function? - actionscript-3

I have multiple MovieClip Symbols published with Flash into FlashDevelop (I'll only use 2 in my example). Each have 3 frames for default, hover and click that I'm using as buttons.
private var btnPlay:PlayButton, btnQuit:QuitButton;
btnPlay = new PlayButton();
btnQuit = new QuitButton();
btnPlay.addEventListener(MouseEvent.ROLL_OVER, onRollOverHandler);
btnPlay.addEventListener(MouseEvent.ROLL_OUT, onRollOutHandler);
btnPlay.addEventListener(MouseEvent.MOUSE_DOWN, onPressHandler);
btnPlay.addEventListener(MouseEvent.MOUSE_UP, onReleaseHandler);
btnPlay.buttonMode = true;
btnPlay.useHandCursor = true;
function onRollOverHandler(myEvent:MouseEvent):void {
btnPlay.gotoAndStop(2);
}
function onRollOutHandler(myEvent:MouseEvent):void {
btnPlay.gotoAndStop(1);
}
function onPressHandler(myEvent:MouseEvent):void {
btnPlay.gotoAndStop(3);
}
function onReleaseHandler(myEvent:MouseEvent):void {
btnPlay.gotoAndStop(2);
}
// Same code for btnQuit here, but replace btnPlay with btnQuit
Instead of adding new EventListeners to every button that do practically the same thing like what I'm doing above, is there a way I could just pass in the button itself to the MouseEvent functions something like this? (I realize this might be difficult since all buttons are their own class)
btnPlay.addEventListener(MouseEvent.ROLL_OVER, onRollOverHandler(btnPlay));
btnPlay.addEventListener(MouseEvent.ROLL_OUT, onRollOutHandler(btnPlay));
btnPlay.addEventListener(MouseEvent.MOUSE_DOWN, onPressHandler(btnPlay));
btnPlay.addEventListener(MouseEvent.MOUSE_UP, onReleaseHandler(btnPlay));
function onRollOverHandler(myEvent:MouseEvent, inButton:MovieClip):void {
inButton.gotoAndStop(2);
}
function onRollOutHandler(myEvent:MouseEvent, inButton:MovieClip):void {
inButton.gotoAndStop(1);
}
function onPressHandler(myEvent:MouseEvent, inButton:MovieClip):void {
inButton.gotoAndStop(3);
}
function onReleaseHandler(myEvent:MouseEvent, inButton:MovieClip):void {
inButton.gotoAndStop(2);
}

Maybe I am misunderstanding, but "event.target" provides you a reference to the button that has been clicked. So if you want to do something to the clicked button, you would write:
myEvent.target.gotoAndStop(1);
Or sometimes you might need to use "currentTarget". You'd still need to create listeners for each function but could use one set of handlers.

Simple answer: No. You could go to some trouble to override the MouseEvent class and allow it to send additional parameters, but why bother in this case? You don't seem to be saving any code.
SLIGHT UPDATE:
Here's a possibly-useful simplification of your original code. It saves a few lines-of-code and uses just a single handler function. Obviously, the 'trace' statements could be replaced by various 'gotoAndStop()' statements:
btnPlay.addEventListener(MouseEvent.ROLL_OVER, HandleAll);
btnPlay.addEventListener(MouseEvent.ROLL_OUT, HandleAll);
btnPlay.addEventListener(MouseEvent.MOUSE_DOWN, HandleAll);
btnPlay.addEventListener(MouseEvent.MOUSE_UP, HandleAll);
function HandleAll(e)
{
if (e.type == "rollOver") trace("rollover");
if (e.type == "rollOut") trace("rollout");
if (e.type == "mouseDown") trace("mousedown");
if (e.type == "mouseUp") trace("mouseup");
}

Related

Evaluate where a function call originated from

Okay so I have a function called changeHandler - it is called by several eventListeners in other functions. I want to write several if statements that evaluate the source of function call and change the dataProvider of my ComboBox depending on the originating function. Example: one of the many functions is called displayCarbs() and has an eventListener like so:
function displayCarbs(event:MouseEvent):void {
myComboBox.addEventListener(Event.CHANGE, changeHandler);
}
(I've removed all of the unnecessary code from the function above)
The if statement inside the changeHandler will look something like this:
if (****referring function = displayCarbs****) {
myComboBox2.dataProvider = new DataProvider(carbItems);
}
I've searched high and low for something that can achieve this, but I just don't have a good enough grasp of AS3 or vocabulary to describe what describe what I mean to get the answer from Google.
The simplest way I can think of... Couldn't you simply create a text string that updates to the name of function before going to changeHandler then in turn changeHandler can check string content and act accordingly..
public var referring_function:String;
function displayCarbs(event:MouseEvent):void
{
referring_function = "displayCarbs";
myComboBox.addEventListener(Event.CHANGE, changeHandler);
}
function displayCarbs(event:Event):void
{
if (referring_function == "displayCarbs")
{ myComboBox2.dataProvider = new DataProvider(carbItems); }
if (referring_function == "displayOthers")
{ myComboBox2.dataProvider = new DataProvider(otherItems); }
// etc etc
}
I cant remember right now if you need == or just = when checking the If statement against strings.
I know there is an accepted answer already, but based on what I gleaned about the problem, here is a solution that wouldn't require adding another variable to check :
function displayCarbs(event:MouseEvent):void
{
myComboBox.addEventListener(Event.CHANGE, changeHandler);
}
function changeHandler(event:Event):void
{
var comboBox:ComboBox = event.target as ComboBox;
if (comboBox.dataProvider == uniqueProvider)
{
myComboBox2.dataProvider = new DataProvider(appropriateItems);
}
}
This should work if the second dataProvider is determined based on the first dataProvider. This of course requires that your uniqueProvider is a class member variable so it has scope within the handler.

How to add event listeners to the numeric stepper's text box?

I have a numeric stepper and I want to add an event listener to its text box:
use namespace mx_internal;
durationStepper.inputField.addEventListener(Event.CHANGE,durationStepperTextInputChanged);
private function durationStepperTextInputChanged(event:Event):void
{
use namespace mx_internal;
trace(durationStepper.inputField.text);
}
However, the event function does not execute! I put a break point there and it does not reach it! What am I missing here? Thanks.
The problem is that the developer has stopped Change event from bubbling up. You can find it if you go to the source file of the NumericStepper. Here are two functions, which prevent you from getting the event.
override protected function createChildren():void
{
super.createChildren();
if (!inputField)
{
inputField = new TextInput();
//some code
//some code
inputField.addEventListener(Event.CHANGE, inputField_changeHandler);
addChild(inputField);
}
}
private function inputField_changeHandler(event:Event):void
{
// Stop the event from bubbling up.
event.stopImmediatePropagation();
var inputValue:Number = Number(inputField.text);
if ((inputValue != value &&
(Math.abs(inputValue - value) >= 0.000001 || isNaN(inputValue))) ||
inputField.text == "")
{
_value = checkValidValue(inputValue);
}
}
As you can see the second function has
event.stopImmediatePropagation();
In this case you have two options: either you should find another way of implementing your logic, or you can copy the source code of the component and eliminate this code line.
It would be fine to override the function, but it is private.
You can read about this common problem here
I have tried to choose the second way. It works perfectly! It is not only the *.as file, but some others, which are used in it.
You can download the component here.

Startdrag is not a function

this.addEventListener(MouseEvent.MOUSE_DOWN,function(e:MouseEvent){this.startDrag(false,null);});
Hi I was wondering why the above doesnt work? Im trying to drag a sprite around screen.
create a sprite on stage, add instance name box, add code to frame one:
box.addEventListener(MouseEvent.MOUSE_DOWN, startMove);
function startMove(evt:MouseEvent):void {
box.startDrag();
}
box.addEventListener(MouseEvent.MOUSE_UP, stopMove);
function stopMove(e:MouseEvent):void {
box.stopDrag();
}
I think your example doesn't work because of the scope of "this" in the event listener handler.
If you remove this.; it will work. It's a scope issue since you use an anonymous function.
You could use the currentTarget of the event, this allows you to make other boxes draggable too, if you add the same listeners.
Note: It is hard to remove an anonymous function as event listener and could cause memory leaks, so the best way is to use a reference to a named function:
box.addEventListener(MouseEvent.MOUSE_DOWN, handleMouseEvent);
box.addEventListener(MouseEvent.MOUSE_UP, handleMouseEvent);
function handleMouseEvent(event:MouseEvent):void
{
switch(event.type)
{
case MouseEvent.MOUSE_DOWN:
{
DisplayObject(event.currentTarget).startDrag();
break;
}
case MouseEvent.MOUSE_UP:
{
DisplayObject(event.currentTarget).stopDrag();
break;
}
}
}

remove ENTER_FRAME EventListener from inside this as3

This is my code in Flash/AS3, in main class.
addEventListener(Event.ENTER_FRAME,function(e:Event){
if(findObject == true){
// I want to remove this ENTER FRAME
}
});
try this:
e.currentTarget.removeEventListener(e.type, arguments.callee)
You shouldn't be doing what you do in the code above.
The mgraph's code has a tiny chance of failing to work as advertised if the currentTarget of the event doesn't have a removeEventListener() method (possible, but very unlikely). From the compiler standpoint though you will be trying to dynamically resolve the method on a generic object which is error prone and should be handled with care. This is hazardous because it shows that the programmer "did not know" what kind of object was she expecting to handle and worked by assumption. Assumptions are great for finding a solution but are equally bad for implementing one.
If you thought of optimizing something in the way you did it, then, just FYI this actually creates a unique (redundant) name in the symbol table (in the compiled SWF file) which causes worse compression of the SWF.
If you are doing this as a matter of experiment, this is fine, but you should avoid such code in real life projects.
One more thing to be aware of: comparison to true constant is 100% useless. If such comparison makes any sense at all (i.e. findObject may evaluate to false any time), then if (findObject) { ... } is equivalent but shorter version of your code.
Last thing, hopefully, the anonymous function is missing return type declaration. It won't really change much in your example, except that you will get compiler warning. Omitting type declaration is, in general, a bad style.
EDIT
public function addEventListener(type:String, listener:Function ...):void
{
this._listeners[type].push(listener);
}
public function dispatchEvent(event:Event):void
{
for each (var listener:Function in this._listeners[event.type])
listener(event);
}
public function removeEventListener(type:String, listener:Function, ...):void
{
delete this._listeners[type][listener];
}
Suppose you actually want to implement IEventDispatcher (instead of using another EventDispatcher - you may have your reasons to do so, one such reason is that native EventDispatcher generates insane amounts of short-lived objects - events, and you may want to reduce that.) But there is no way you can replicate event.target or event.currentTurget in your code because you can't access the object owning the method, so, you would leave that out.
Another example:
public class SomeEvent extends Event
{
private var _target:NotEventDispatcher;
public function SomeEvent(type:String, someTarget:NotEventDispatcher)
{
super(type);
this._target = someTarget;
}
public override function get target():Object
{
return this._target;
}
}
This is something that I actually saw in real world, this was used in either Mate or similar framework to sort of "anonymously" connect all event dispatchers to a single static instance of some "mothership event dispatcher".
I don't necessarily justify this approach, but, technically, nothing stops you from doing either one of these. What I was saying in my post above is that in certain situations the language promises you things, like, if you did:
var dispatcher:IEventDispatcher;
try
{
dispatcher = IEventDispatcher(event.currentTarget);
// now you can be sure this object has removeEventListener
dispatcher.removeEventListener(event.type, arguments.callee);
}
catch (error:Error)
{
// but what are you going to do here?
}
But the most common case would be you subscribing to a bubbling event, in which case, you don't know whether you want to unsubscribe from event.target or event.currentTtarget - because you don't know which one is that you are listening to.
I agree with wvxvw.
Another way to approach your problem is to have a variable to control the "state" of your ENTER_FRAME event:
private var _state:String;
private function init(e:Event):void {
addEventListener(Event.ENTER_FRAME, loop, false, 0, true);
}
private function loop(e:Event):void {
switch(_state) {
case "play":
// do play stuff
// when you want to pause
// goToPause();
break;
}
}
// you can call the method below from a button or whatever you want
private function goToPause():void {
_state = "pause";
// do some stuff here
// when you are done, switch "_state" back to "play"
}
In this example, you keep listening for ENTER_FRAME, but it only does things when the _state variable is set to "play". You can also remove the event listener in the goToPause method:
private function goToPause():void {
_state = "pause";
removeEventListener(Event.ENTER_FRAME, loop);
}
However, the nice thing about using the "_state" to switch things is that you don't end up having a mess of addEventListeners and removeEventListeners (which is what can happen depending on how complicated your loop gets) that you have to keep track of.
You should not use anonymous function call if you would like to remove listener some time later.
public function main():void
{
//...
//some method, where you add event listener
//...
//adding enterFrame event listener
this.addEventListener(Event.ENTER_FRAME,enterFrameHandler);
//...
}
private function enterFrameHandler(e:Event)
{
if(findObject) // " == true" is not really necessary here.
{
// removing enterFrame listener:
this.removeEventlistener(Event.ENTER_FRAME,enterFrameHandler);
}
}
Just for a completeness with the other techniques mentioned here, the function you are creating is a unbound closure, so you can also leverage that concept to reference both your function and dispatcher.
var callback:Function;
var dispacher:IEventDispatcher = this;
addEventListener(Event.ENTER_FRAME, callback = function(e:Event){
if(findObject == true){
dispacher.removeEventListener(Event.ENTER_FRAME, callback);
}
});
Normal closed-over variable rules apply.

effcient Event dispatchinging in Actionscript 3

I have 6 instances of a moiveClip. when one is clicked, i need to write a function that affects all other instances of the movieClip, and not affect the one being clicked.
What is the most efficient way of doing this? Im thinking something to do with event class for sure.aa
Put a single event handler on all of them and do something like this:
private function onClickMovieClip(event:MouseEvent):void
{
for (/*run through your clips*/)
{
if (event.target != /*current clip*/)
{
doSomething();
}
}
}