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
Related
I am using JavaFX properties since JavaFX 8.0 , they seem to miss something appropriate i think . Let's say i add a change listener to a JavaFX Property :
DoubleProperty doubleProp = new SimpleDoubleProperty(1);
doubleProp.addListener((observable,oldValue,newValue)->{ ...code here }));
and i want to add 3 more including and InvalidationListener
Why to create an instances of ChangeListenerJavaDoc or InvalidationListenerJavaDoc?
Adding lines of code like :
ChangeListener<? super Number> listener = (observable , oldValue , newValue) -> {
if (newValue.intValue() == 1)
//..... code
};
all over the place isn't clear.
Why methods like these doesn't exist:
doubleProp.getChangeListeners().clearAll();
or
doubleProp.getChangeListeners().remove(doubleProp.getChangeListeners().get(0));
or
doubleProp.remove(doubleProp.getChangeListeners().get(0));
or
doubleProp.getInvalidationListeners().get(0));
Does JavaFX 9.0 has methods like these ? Is what i want a bad design ? I need to know the above :).
Allowing access to a collection of all listeners on a property would be a bad design as it would break encapsulation for controls (or other objects) that used those properties. (Specifically, a control would likely want to expose a property while registering listeners on that property and keeping those listeners private. If the property exposed the listeners, this would become impossible.)
Just as one example, if StringProperty exposed a ObservableList<ChangeListener<String>> getListeners() method, then the API would make the following possible:
Label label = new Label("Some text");
label.textProperty().getListeners().clear();
This would completely break the label. The label's skin registers a listener with the label's textProperty(), that ensures the skin updates if the text is changed. If you remove this listener, which is the only possible result of executing the code above, then the label's skin would not know it had to resize or even display new text when you called label.setText(...).
If you need to register a listener that you might need to remove, you just need to retain a reference to it. The overhead in code is minimal, i.e. there is not much difference between
label.textProperty().addListener((obs, oldText, newText) -> { /* code */ });
and
ChangeListener<String> listener = (obs, oldText, newText) -> {/* code */} ;
label.textProperty().addListener(listener);
#James_D, your explanation about what can go wrong when a listener is carelessly removed is good. However, this is really a developer problem, not design. Indeed, it is bad design for any 'add/remove' pattern not to also include access to whatever has been added.
For example, it may be useful to remove ("suspend") all the listeners temporarily in order to perform a process that changes the value (indeed several times) where the value at the end of the process is the same as the start; when the process is finished the listeners are added back ("restored"). While the 'reference' solution works for listeners you know about when designing a control, it doesn't help for listeners added by a developer using your control - these can't be referenced because you don't know what they will be. The 'suspend/restore' technique deals with this, it's up to the developer to use it properly and in the right situation.
JavaFX's property enhancements (object properties, bindings etc) are a huge improvement over Swing, like moving from a covered wagon to a Bugatti. However, the omission of a 'getListeners()' feature is a drawback.
I have a flex application, the display of this application is build with many containers.
I have a FlexEvent.UPDATE_COMPLETE on each of the displayObjects.
What do I want to accomplish?
I want to handle the event only on the top level where it occurred, for instance, if I have a grid and the update occurred in a label somewhere inside, I want to handle the event only on the Grid.
is there a way to accomplish that?
just to emphasize, I don't have any knowledge of the display objects at compile time, only at runtime, the display is being built dynamically to I can't just write the code on the grid, I have to check somehow if the event occurred in a higher level.
I would love some help with this issue, even if it's not code but concept of how to handle this unique issue.
Thanks
Have you considered stopPropagation()/stopImmediatePropagation() on the event, once you handle that event.
Example:
Since your button is in canvas. Your event handler method in canvas would look like this,
function handleEvent(e:FlexEvent):void {
trace("In Canvas's handler");
//do your events...
e.stopPropagation(); //This stops from propagating e to its parent containers, which is an HBOX. The container can be anything at runtime, it doesnt affect the propagation.
}
Try the same example in your other containers too.
Some examples here,
http://livedocs.adobe.com/flex/3/html/help.html?content=events_08.html
http://livedocs.adobe.com/flex/3/langref/flash/events/Event.html#stopPropagation%28%29
Just check for the event.target and ignore if it is not what you're looking for. Or even better: listen for events on top level components and ignore if target and currentTarget doesn't match.
if(event.target != event.currentTarget)
return;
If you can't do this either, check the parents: if parent is your application or the container that holds the top level items, it is a top level item. Based on the structure of your component, it can be anything like
if(event.target.parent == this)
//or
if(event.target.parent == this.theContainer_thatHolds_topLevelItems)
//or
if(event.target.parent is Application)
//or
if(event.target.parent is CustomContainerClassName)
Flex 3 question:
I trying here to avoid having to bind resources to all my components labels ( ie a button) and find a way to have this automated.
Problem:
It corrupts the layout in design mode to bind directly in the mxml label="{resourceManager.getString('myResources', 'submit')}" and makes the design view useless. but when declaring bindings elsewhere, in actionScript or via a bind tag, it is counter productive and prone to many errors and miss.
Proposition:
I would like to create my own button that automatically invoke resources to localize a button label. So the author puts "Submit" in the mxml description of my button, and when running it would take the value of the label ie "submit" and use resourceManager.getString('myResources', 'submit').
but I can't find the way to override the set label function, Is it possible if yes how? else how can I go about it?
Maybe I am missing an essential process here that would make the use of resources more elegant, as well as how to override such thing as a button's label.
Thanks for your advices.
Create a component called MyButton, extending Button. Then use this:
override public function set label(value:String):void {
super.label = resourceManager.getString('myResources', value) || value;
}
Assuming the resource manager returns "null" or "undefined" this will work, and will only replace the value if it exists in "myResources".
If you don't want to override every component you need to do this with, then you can add a FlexEvent.CREATION_COMPLETE event on every component. Then use a single generic function to do your label localization.
I am adding DisplayObjects to a Canvas using
ContentContainer.addChild(c);
Where ContentContainer is my Canvas object and c is the DisplayObject I have created at run-time
Some of these DisplayObjects also have children of there own which are added at run-time prior to the DisplayObject being added to the Canvas
I then need to iterate over all the children of ContentContainer but the first time I do this, it says that ContentContainer has no children (ie, ContentContainer.numChildren = 0). If I do it again tho then it is fine and returns the correct number of children.
Is there something I need to call to get ContentContainer to recalculate how many children it has?
As Michael noted it would be helpful to see the code but you might want to look into the Event overview and About the creation policy sections in the docs - http://livedocs.adobe.com/flex/3/html/help.html?content=containers_intro_3.html
Specifically the childAdd event might be what you want to listen for before you iterate over it:
add Dispatched by a component after the component has been added to its container and the parent and the child are in a consistent state. This event is dispatched after the container has dispatched the childAdd event and all changes that need to be made as result of the addition have happened.
=Ryan
ryan#adobe.com
I did a similar task with a callLater in order to wait till after a dragdrop completed before recalculating some tasks. This might work for you.
public function myFunct():void{
//do your adding
callLater(
function():void{
//do your loop
}
)
}
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 :))