Avoid FocusOut event trigerred when apllication loses focus - apache-flex

I have done an override of the standard TextInput component
In this component I have :
addEventListener( FocusEvent.FOCUS_OUT, handleFocusOut );
My method is triggered when the field loses focus for another field (nice)
Problem : It is triggered also when the whole flex application loses focus (when my field has the current focus inside my form)
Questions :
What have I done wrong ?
Is there a way to avoid doing stuff when it is a application-focusout-event ?
Regards

I am not sure why this is behaving this way. But one solution might be to have an eventListener for FOCUS_OUT event at the application level and call stopImmediatePropagation().

Thanks for your help !
Here is what I have done in my component (textinput child)
Add two event handler :
- addEventListener( Event.ACTIVATE, handleEventActivate );
- addEventListener( Event.DEACTIVATE, handleEventDeActivate );
They update the internal field _isApplicationActive
I handle the focusOut event :
addEventListener( FocusEvent.FOCUS_OUT, handleFocusOut );
in the method I have
if (!_isApplicationActive) { event.stopImmediatePropagation(); }
With this my focusOut handling functions are not called when the app is deactivated
Because => DECACTIVATE events are called before FocusOut events !

The easy answer is to check if event.relatedObject (the object receiving focus) is null. Flex's FocusManager tries really hard to ensure some flex object has (flex) focus, so it should not be null otherwise.
Do also check isRelatedObjectInaccessible if you might need to.

Related

Can I disable CHANGE event in a custom component?

I have a custom MXML component which has a change event declared as:
<mx:Metadata>
[Event(name="change", type="flash.events.Event")]
</mx:Metadata>
The problem is that this event is dispatched whenever I change ANYTHING inside the component including a simple var. There are times when I want to be able to change the value of a var in the component without dispatching a change event. Is there a simple way of disabling the change event and then re-enabling it once I have made the change I want?
I tried to use removeEventListener("change") but it appears I can only do that for a function that has an event listener added. Same for removeEventListener(Event.CHANGE).
Surely there must be a simple way of disabling events declared in
mx:Metadata
yes there are methods on event you can use. So although the event is still dispatched, this gives you complete control of what happens with it.
// first set the useCapture flag to true
// this tell flex that onChange gets the event before it starts bubbling
myCustomComponentThatDispatchesALotOfChangeEvents.addEventListener(Event.CHANGE, onChange, true);
private function onChange(event:Event):void{
// here is the method you want
// this stops the event from bubbling and lets you handle
// all functionality in this listener only
event.stopImmediatePropogation();
// now look at what happened and see if you want to
// do anything else based on what actually changed
}
as a side note, you can also look at Event.preventDefault() which cancel's the events default behavior
"change" is also a flex thing. It you want to only dispatch the event in one particular scenario, make a new event class that SubClasses Event like MyChangeEvent. The when you make your change...
dispatchEvent(new MyChangeEvent(MyChangeEvent.STUFF_CHANGED))
then
myCustomComponentThatDispatchesALotOfChangeEvents.addEventListener(MyChangeEvent.STUFF_CHANGED, onChange);

Flex AsyncToken for listening to Alert box buttons

Can I listen to Alert button click between components using AsyncToken?
Basically, I want to have a method that opens an Alert with buttons and have it return an AsyncToken so that other components calling that method can listen for button click.
Example:
var token:AsyncToken=methodThatOpensAlert();
token.addResponder(new mx.rpc.Responder(buttonClick));
What's the way to do that?
Thank you.
You might be able to use an AsyncToken to achieve this but you could also just register for custom events that you dispatch from the pop up, this is a much cleaner method IMO. Really you've got two relatively clean options I can think of. 1 you make your pop-up dispatch events like "okClicked" "cancelClicked" for different button clicks within the pop-up, you create an instance of the pop up and add listeners then call PopUpManager.addPopUp, or else you do PopUpManager.createPopUp and keep a reference to the returned display object (the instance of the pop-up it created) and add your listeners then. 2 you make two properties in the pop up typed as function, you use them as call backs, so when you create the pop-up you set the okClickedFunction and cancelClickedFunction (or whatever your buttons may be) then in the pop-up you put cilck handlers on the buttons, check to see if the appropriate call-back function is set and call it if so, like
if(okClickedFunction)
okClickedFunction();
Let me know if you have a specific need that makes you think you must use the AsyncToken, but from checking out the docs it looks as though it's strictly meant to work with the other RPC methods and lots of properties are read-only.
EDIT:
[SomeUtilClass.as]
private static function methodThatOpensAlert():CustomAlert
{
return PopUpManager.createPopUp(Application.application, CustomAlert) as CustomAlert;
}
[CustomAlert.as]
[Event(type="flash.events.Event", name="button1Clicked")]
[Event(type="flash.events.Event", name="button2Clicked")]
private function button1Clicked_handler(event:MouseEvent):void
{
dispatchEvent(new Event("button1Clicked", true));
}
private function button2Clicked_handler(event:MouseEvent):void
{
dispatchEvent(new Event("button2Clicked", true));
}
[ThingThatUsesAlert]
var ca:CustomAlert = SomeUtilClass.methodThatOpensAlert();
ca.addEventListener("button1Clicked", button1ClickHandler);
ca.addEventListener("button2Clicked", button2ClickHandler);
And I believe mouse events bubble by default anyhow still so you could really just listen for a click event on the pop up then use the event.target to determine if it was one of the buttons your interested in.
Let me know if you can make sense of this or need more info.

how to get event type that is fired

I am working on Flex project these days and having java background. In my current task, same pop up is opened when two different types of custom events are being fired and I have to hide a button for one event type. So, how i can get event type.
Thanks in advance.
The Event class has a property called type wich is a string stating what kind of event it is.
function eventHandler(event:Event):void {
trace(event.type);
}
Generally speaking, you can get it this way:
mc.addEventListener(MouseEvent.CLICK, myMethod);
function myMethod(evt){
trace(evt.type);
}

Flex: Lose Component Focus

I have a (hopefully) quick question. I've got some stepper boxes. Though really this could apply to any interactive component. I want the selected box to lose focus when when I click anywhere else ( stage included ). Is there an easy way to do this? I can't seem to find an effective way to make it lose focus.
In case anyone else finds their way here seeking a solution to this problem, here is the answer:
private function onGlobalMouseUp(event : MouseEvent) : void {
var fm:FocusManager = new FocusManager(stage);
//Since Flash Player can set focus on subcomponents as well as on components themselves,
//findFocusManagerComponent is used to find the component that either has focus or contains the subcomponent
//that has focus. If, for example, a TextField contained within a TextArea component has focus, findFocusManagerComponent
//will return the TextArea component, and not the TextField. This being the case, we can definitely determine
//whether the target object of the MouseUp event is a component (or is part of a component). If the target
//object is NOT a component (nor contained within one), then we clear all component focus.
if(fm.findFocusManagerComponent(event.target as InteractiveObject) is UIComponent){
//target of MouseUp is either a UIComponent, or is contained within a UIComponent, so do nothing.
}else{
//target of MouseUp is neither a UIComponent, nor is it contained within a UIComponent, so set component focus to null.
fm.setFocus(null);
}
}
So here's the solution I've come up with that works very well. I have a function called add() which has been assigned to applicationComplete. In that function I include:
this.skin.addEventListener( MouseEvent.MOUSE_UP, loseFocus );
Which calls:
private function loseFocus( e : MouseEvent ) : void
{
if ( e.eventPhase == EventPhase.AT_TARGET )
{
this.focusManager.deactivate();
}
}
Simple enough, and does what I was looking for. "Phase" filter is necessary to keep other components from registering the clicks.
As an important note: this.skin needs to be the event target. The stage is never exposed to the mouse in a Flex application.
Example Application Code
If someone has a better solution, please suggest one!
Perhaps you should check out FocusManager.hideFocus().
Maybe tie it into the focusOut event of your UIComponent.
Flex API

Flex 3 keyboard event handling

I'd like to arrange things so that I have a chain of keyboard event handlers in my flex application, all of whom are queried when key down events occur. Basically, when a visual component is on screen, it is a candidate for handling a key press event. Something like this (clearly this is pseudocode):
<application handles_keys="F5, F6">
<tabGroup>
<tab1 handles_keys="pgup, pgdn">
<control handles_keys="0,1,2,3,4,5,6,7,8,9" />
</tab1>
<tab2 handles_keys="pgup, left, right"/>
</tabGroup>
</application>
I have a class written that will respond to the key events the way I want it to, so how do I register one or more instances of this class to have the results I want? Also, note that there are some situations where this class should receive events that would ordinarily be handled by a UI component. The TAB key is the main example; I have a few cases where I want my key down event handler to fire even when the focus is on a text field.
The way you have your pseudocode setup right now, you'd have to subclass all the different containers and add a handles_key property to each one. You may want to externalize the functionality to a separate class like this:
<KeyHandler target="{tab1}" handlesKeys="pgup,left,right"/>
As for actually catching the events, you'll need to add a KeyboardEvent.KEY_DOWN listener on the UIComponent you're wanting to listen to. You'll need to set the useCapture argument of addEventListener() to true as well. This will let you capture the event and prevent it instead of the event hitting the object and bubbling up.
target.addEventListener(KeyboardEvent.KEY_DOWN, target_onKeyDown, true);
Inside your target_onKeyDown event, check to see if you have a match for one of your keys you want to handle and if there is a match, call event.stopImmediatePropagation() or event.preventDefault() depending on what you need to do.
The Flex 3 Language Reference gives a good explanation of event propagation and keyboard events:
http://livedocs.adobe.com/flex/3/langref/flash/events/Event.html
The correct approach turns out to have been a global keyboard event manager, added as a key down listener to the stage when the application's creationComplete event is called. This then dispatches domain events for each keypress or combination thereof. Sadly, the filtering per-component model didn't work out.
I'm going to be porting this app to the Cairngorm framework, which should work really well once I'm done it.
when the displayed object is added to screen then start listen for stage keyboard events
when the object was removed from the screen the remove the keyboard event listener
on keyboard events filter the events you need :)
The code for a Canvas class you need should look like this:
class MyCanvas extends Canvas
{
public function MyCanvas(){
super();
}
override protected function createChildren():void{
super.createChildren();
this.systemManager.stage.addEventListener(KeyboardEvent.KeyUp, onKeyUpHandler);
}
private function onKeyUpHandler(e:KeyboardEvent):void{
// handle your code
switch(e.charCode){
case Keyboard.1:
case Keyboard.2:
case Keyboard.3:
case Keyboard.4:
case Keyboard.5:
case Keyboard.6:
case Keyboard.7:
case Keyboard.8:
case Keyboard.9:{
// do my stuff
break;
}
case Keyboard.F1:{
// do other stuff
break;
}
}
}
}
public function destroy():void{
//don't forget to remove listeners for stupid flash garbage collector
this.systemManager.stage.removeEventListener(KeyboardEvent.KeyUp, onKeyUpHandler);
}
}
Ignore any miss-spells :D I wrote the code from my mind :))

Resources