How to get mouse and keyboard events, masked by PopUpManager - apache-flex

I am implementing an application timeout feature (flex4). What I am finding is that mouse and keyboard events, which I have listened to with :
FlexGlobals.topLevelApplication.addEventListener(MouseEvent.MOUSE_MOVE, resetLastActivity);
FlexGlobals.topLevelApplication.addEventListener(KeyboardEvent.KEY_DOWN, resetLastActivity);
are being masked by the existence of any popup windows. The code is in a component, in the constructor. The component is added to the main application in the block.
How can I get these system generated events to not get stopped by PopUpManager display objects?
Thanks!

Try listening on the Stage instead of the topLevelApplication. access the stage using the stage property on the topLevelApplication
I think topLevelApplication formally returns an object, so you'll need to do something like this:
(FlexGlobals.topLevelApplication as Application).stage.addEventListener(MouseEvent.MOUSE_MOVE, resetLastActivity);
(FlexGlobals.topLevelApplication as Application).stage.addEventListener(KeyboardEvent.KEY_DOWN, resetLastActivity);
Update:
Keep in mind that the stage is not set in the topLevelApplication until that component's creationComplete event is fired. If you are adding event listeners to the stage in a non UI class; you have to make sure this is not done until creationComplete fires in the topLevelApplication.
To do this, add an event listener to the topLevelApplication's creationComplete method in the constructor.
(FlexGlobals.topLevelApplication.addEventListener(FlexEvent.CREATION_COMPLETE, onCreationCompete);
If this is an MXML UIComponent, you can add that code in a preinitialize event handler instead of a constructor.
Then this would be the creation complete handler:
public function onCreationComplete(event:FlexEvent):void{
(FlexGlobals.topLevelApplication as Application).stage.addEventListener(MouseEvent.MOUSE_MOVE, resetLastActivity);
(FlexGlobals.topLevelApplication as Application).stage.addEventListener(KeyboardEvent.KEY_DOWN, resetLastActivity);
}

This works more elegantly without bothering creationComplete.
FlexGlobals.topLevelApplication.systemManager.addEventListener(MouseEvent.MOUSE_MOVE, resetSessionTimer);
FlexGlobals.topLevelApplication.systemManager.addEventListener(KeyboardEvent.KEY_DOWN, resetSessionTimer);

Related

Tornadofx onFocus listener

Is there something like an onFocus() method, which I could override like the onDock() and onCreate() in the view class?
In the documentation there is only written about live reloading of views.
I tried combining that with, the onDock() and onCreate() method, but, even though it "works", it's not a very neat way of replicating onFocus behaviour.
Is there a simple way to have a "listener" method that's called when the view/fragment comes to front/on focus?
The View is a container, and not an UI element in the sense of the JavaFX context, so it cannot receive an onFocus callback. However, you can register one with the current window or even the root node of the View. If you're opening a window, you could register such an even with the currentWindow property. If you're not opening a window, you could register it with the root property of the View. Here is an example listening for a single focus change event from the currentWindow:
override fun onDock() {
currentStage?.focusedProperty()?.onChangeOnce {
}
}

JavaFX TextArea: Listener and event handler dependency

When I type a character in a TextArea, I want to both handle the event of "new typed character" as well as "cursor position changed". By using the following listener and handler, this works.
textArea.selectionProperty().addListener(new SelectionListener());
textArea.addEventHandler(KeyEvent.KEY_TYPED, keyTypedHandler);
(SelectionListener implements ChangeListener)
However, when I decide to consume the event in keyTypedHandler, the listener's change() method isn't called anymore. For this task I want to consume the event because the textArea's UI should not update!
Any hints appreciated, thanks!

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

Why does BindingUtils.bindProperty() not work immediately?

I have a two way binding between a loaded flash file and the main application in flex.
BindingUtils.bindProperty(this, "micGainValue", audioPublisherApp, "micVolume");
BindingUtils.bindProperty(audioPublisherApp, "micVolume", this, "micGainValue");
micGainValue=75;
However, the setting of micGainValue does not set micVolume in the flash file. I instead tried setting micGainValue after 200 frames, and it now does set micVolume. Is there a way to test that these properties are bound and so set the value after?
EDIT:
The flash file was actually changing the value. Now the question is, why does setting micVolume not change micGainValue.
This the code from my loaded flash file:
[Bindable]
public function get micVolume():Number{
if(microphone!=null)
return microphone.gain;
return 0;
}
public function set micVolume(val:Number):void{
if(microphone!=null)
microphone.gain=val;
}
Flex databinding is implemented using events. When you use BindingUtils.bindProperty, what is happening behind the scenes is that an event listener is being added to the target object to listen for an event of type PropertyChangeEvent
If the target object does not dispatch the PropertyChangeEvent when it is changed, then binding will never be triggered.
When you add the [Bindable] attribute to properties in Flex, what you are doing is telling the framework to dispatch the PropertyChangeEvent when that property is changed. If you don't include the attribute (or put it on the class) then the event is not dispatched and binding doesn't happen.
That's why your binding is working from Flex to Flash but not the other way around- The Flex object is dispatching the required event when it is changed but the flash object is not.
Here is the info on PropertyChangeEvent
Personally, for Flash -> Flex I would dispatch my own event when the flash part changes its values and use a handler on that to update a bindable object within the Flex part. You can then bind other Flex stuff to that.

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