Alert and mouse & key events - actionscript-3

When showing an alert box with mx.controls.Alert.show() and clicking it's buttons with the mouse (or Enter key) or clicking anywhere, these events are passed to the parent window as well, eventually triggering buttons there etc.
Is there a straight forward way to prevent this, like setting an attribute of the alert instance?

If you set the closeHandler parameter in show() you can then call event.stopPropagation() to prevent the event from being processed on subsequent nodes.
Code would look something like this:
Alert.show("Message", "Title", Alert.OK, parent, onClose);
function onClose(event:CloseEvent):void
{
event.stopPropagation();
// Do close stuff here
}
Edit
Added example for Flex 4.6, in Flash Builder 4.6:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication
xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
creationComplete="onCreationComplete(event)">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.events.FlexEvent;
private function onCreationComplete(e:FlexEvent):void
{
addEventListener(MouseEvent.CLICK, onAppClick);
showAlert();
}
private function showAlert():void
{
Alert.show("An Alert", "Alert Title", Alert.OK | Alert.CANCEL, this, onAlertClose);
}
private function onAlertClose(e:CloseEvent):void
{
e.stopPropagation();
trace("Alert Close");
}
private function onAppClick(e:MouseEvent):void
{
trace("App Click");
}
private function onBtnClick(e:MouseEvent):void
{
trace("Button Click");
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout
gap="12"/>
</s:layout>
<s:Button
label="A Clickable Button"
click="onBtnClick(event)"/>
<s:Button
label="Show Alert"
click="showAlert()"/>
</s:WindowedApplication>

Related

AS3 Shortcut window and pop up

I have an AIR application with several windows.
I have set the shortcut key ESC to close window. It's works well.
On creationComplete, I have this code :
this.addEventListener(KeyboardEvent.KEY_DOWN, exit_keyDownHandler);
and
protected function exit_keyDownHandler(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.ESCAPE){
//
this.removeEventListener(KeyboardEvent.KEY_UP, exit_keyDownHandler);
stage.nativeWindow.close();
}
}
But on this window, I could open a popup window where I have set same shortcut (ESC) to remove popup.
After opening and closing popup window shortcut on main window (first), has no effect !
My code to open popup is as follows:
wpTL = new wAddEditTL();
PopUpManager.addPopUp(wpTL, this,true);
PopUpManager.centerPopUp(wpTL);
On popup window extend TitleWindows, I add this event :
this.addEventListener(KeyboardEvent.KEY_DOWN, exit_keyDownHandler);
I hope a programming expert can help me, thank you very much!
I had some time to test this.
Here is a simple solution that works on my side with both MX and Spak Window components.
First, we create a simple application (Main.mxml) with only two buttons (to open MX or Spark Window) :
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
name="Key Events Test"
horizontalAlign="center"
verticalAlign="middle"
creationComplete="creationCompleteHandler(event)"
paddingLeft="0"
paddingTop="0"
paddingBottom="0"
paddingRight="0"
frameRate="60"
width="320"
height="200">
<mx:Button id="sparkWindowButton"
label="New Spark Window"
click="sparkWindowButton_clickHandler(event)"/>
<mx:Button id="mxWindowButton"
label="New MX Window"
click="mxWindowButton_clickHandler(event)"/>
<mx:Script>
<![CDATA[
import mx.core.Window;
import mx.events.FlexEvent;
import spark.components.Window;
private function creationCompleteHandler(event:FlexEvent):void {
NativeApplication.nativeApplication.addEventListener(KeyboardEvent.KEY_DOWN, systemManager_keyDownHandler);
}
private function systemManager_keyDownHandler(event:KeyboardEvent):void {
if (event.keyCode == Keyboard.ESCAPE) {
var currentWindow:NativeWindow = NativeApplication.nativeApplication.activeWindow;
currentWindow.stage.nativeWindow.dispatchEvent(new Event(Event.CLOSING));
}
}
private function sparkWindowButton_clickHandler(event:MouseEvent):void {
var nativeWindow:spark.components.Window = new MySparkWindow();
nativeWindow.open();
}
private function mxWindowButton_clickHandler(event:MouseEvent):void {
var nativeWindow:mx.core.Window = new MyMXWindow();
nativeWindow.open();
}
]]>
</mx:Script>
</mx:Application>
Then we create a Popup Component (PopupPanel.mxml) :
<?xml version="1.0"?>
<mx:Panel xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
title="POPUP"
verticalAlign="middle"
width="280"
height="120">
<mx:Label text="HEY"
textAlign="center"
width="100%"/>
</mx:Panel>
And finaly, we create 2 components :
The MX Window (MyMXWindow.mxml) :
<?xml version="1.0"?>
<mx:Window xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
horizontalAlign="center"
verticalAlign="middle"
width="320"
height="200"
creationComplete="creationCompleteHandler(event)"
showStatusBar="false">
<mx:Button id="popupButton"
label="Add a popup"
click="popupButton_clickHandler(event)"/>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
public var popup:PopupPanel;
private function creationCompleteHandler(event:FlexEvent):void {
this.title = "MX Window #" + NativeApplication.nativeApplication.openedWindows.length;
this.stage.nativeWindow.addEventListener(Event.CLOSING, closingHandler, false, 0, true);
}
private function popupButton_clickHandler(event:MouseEvent):void {
popup = new PopupPanel();
PopUpManager.addPopUp(popup, this, true);
PopUpManager.centerPopUp(popup);
}
private function closingHandler(event:Event):void {
if (popup != null && popup.isPopUp) {
event.preventDefault();
trace("CLOSING POPUP");
PopUpManager.removePopUp(popup);
} else {
trace("CLOSING WINDOW");
stage.nativeWindow.close();
}
}
]]>
</fx:Script>
</mx:Window>
And finally, the Spark Window (MySparkWindow.mxml) :
<?xml version="1.0"?>
<s:Window xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
width="320"
height="200"
creationComplete="creationCompleteHandler(event)"
showStatusBar="false">
<s:layout>
<s:VerticalLayout horizontalAlign="center"
verticalAlign="middle"/>
</s:layout>
<s:Button id="popupButton"
label="Add a popup"
click="popupButton_clickHandler(event)"/>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
public var popup:PopupPanel;
private function creationCompleteHandler(event:FlexEvent):void {
this.title = "Spark Window #" + NativeApplication.nativeApplication.openedWindows.length;
this.stage.nativeWindow.addEventListener(Event.CLOSING, closingHandler, false, 0, true);
}
private function popupButton_clickHandler(event:MouseEvent):void {
popup = new PopupPanel();
PopUpManager.addPopUp(popup, this, true);
PopUpManager.centerPopUp(popup);
}
private function closingHandler(event:Event):void {
if (popup != null && popup.isPopUp) {
event.preventDefault();
trace("CLOSING POPUP");
PopUpManager.removePopUp(popup);
} else {
trace("CLOSING WINDOW");
stage.nativeWindow.close();
}
}
]]>
</fx:Script>
</s:Window>
Now, the explaination of what we are doing :
In Main.mxml, we are listening to the keyboard events for the whole application (so there's no problem with focus on a particular component or window).
When we catch the ESCAPE keycode, we retrieve the instance of the active application window and send it an Event.CLOSING event to indicate that we are closing the window.
In the window (MyMXWindow.mxml or MySparkWindow.mxml), we retrieve this event and check if the PopUp is open. If so, it is closed and the window continues to work, otherwise we close the window.
I do not know if this is what you want to do, but I hope at least it will point you to the right solution for your project.
Happy coding with Flex and AS3 ;-)

call a function when component visibility changes

Pretty simple thing but I am stuck.
Question: I want to call a function when the visibility of my component changes so I can do some clean up.
I have tried using the FlexEvents FlexEvent.HIDE and FlexEvent.SHOW and specified the function to call in my mxml header
show="onShow(event)"
private function onShow(event:FlexEvent):void
{
trace("********** onShow***********");
}
That didn't work. I then tried adding various eventListeners but that didn't work, Am I using listening for the wrong events?
addEventListener(FlexEvent.SHOW, onShow, false, 0, true);
addEventListener(FlexEvent.STATE_CHANGE_COMPLETE, onHide, false, 0, true);
And finally I tried overriding the setter for visible but that threw errors
override public function set visible(value:Boolean):void
{
super.visible = value;
visible = value;
}
You are right when using FlexEvent.HIDE and FlexEvent.SHOW but I don't know why you didn't get what you want. Take this simple example where a button hide a second one and when this last is hidden it disable the first one. A third button show the second one which when it is visible enable the first button :
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" creationComplete="init(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function button_02_hideHandler(event:FlexEvent):void
{
button_01.enabled = false;
}
protected function button_01_clickHandler(event:MouseEvent):void
{
button_02.visible = false;
}
protected function button_03_clickHandler(event:MouseEvent):void
{
button_02.visible = true;
}
protected function init(event:FlexEvent):void
{
button_02.addEventListener(FlexEvent.SHOW, function(e:FlexEvent){
button_01.enabled = true;
})
}
]]>
</fx:Script>
<s:Button id="button_01" x="68" y="93" label="Button 01" click="button_01_clickHandler(event)"/>
<s:Button id="button_02" x="170" y="93" label="Button 02" hide="button_02_hideHandler(event)"/>
<s:Button id="button_03" x="276" y="93" label="Button 03" click="button_03_clickHandler(event)"/>
</s:Application>

Simple flex popup with dispatch event in child and listener in parent not working

Parent.mxml
This file is calling the popup class below when the button is clicked.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.managers.PopUpManager;
var popup:pop = null ;
protected function clickHandler(event:MouseEvent):void
{
popup = PopUpManager.createPopUp(this,pop,true) as pop;
popup.ok.addEventListener(MouseEvent.CLICK, captureComments);
popup.close();
}
var str:String="";
private function captureComments():void{
Alert.show("Invoked Event Listener", "Alert");
str=popup.comments;
}
]]>
</fx:Script>
<mx:Button id="id1" label="Click" click="clickHandler(event)"/>
<s:Label id="lbl" height="18" width="282" text={str} />
</s:Application>
Child.mxml
This file is the popup reference, creating popup.
I have configured the close action and cancel buttons to work as needed, but unable to propagate the text entered in comment are back to the parent.
<?xml version="1.0" encoding="utf-8"?>
<mx:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
layout="vertical" width="524" height="322"
showCloseButton="true"
close="close()" chromeColor="#CCCCCC"
horizontalAlign="center" verticalAlign="middle" color="#000000">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.managers.PopUpManager;
import mx.rpc.events.ResultEvent;
[Bindable]public var comments:String;
public function close(): void{
PopUpManager.removePopUp(this);
}
private function save(): void{
if(comments == null){
comments = "";
}
dispatchEvent(new ResultEvent(comments));
}
]]>
</fx:Script>
<mx:HBox width="100%" height="70%">
<mx:VBox width="100%" height="100%">
<mx:TextArea id="comment" text="{comments}" width="100%" height="80%" change="comments = event.target.text">
</mx:TextArea>
<mx:HBox horizontalAlign="center" width="100%" height="20%">
<s:Button id="ok" label="OK" chromeColor="#CCCCCC" click="save()" fontWeight="bold"/>
<s:Button id="cancel" label="Cancel" chromeColor="#CCCCCC" click="close()" fontWeight="bold"/>
</mx:HBox>
</mx:VBox>
</mx:HBox>
</mx:TitleWindow>
You are dispatching a ResultEvent, like this:
dispatchEvent(new ResultEvent(comments));
However, the event type is the user entered input. Check out the ResultEvent constructor. The first argument is the event type. I have no idea how you'll be able to consistently listen for an event type that is unknown at compile time.
I think you are trying to pass your custom data back to your parent class. My preference would be to use a custom event for this; but if you wanted to use a ResultEvent you could pass your comments in the result property:
dispatchEvent(new ResultEvent(ResultEvent.RESULT,false,true,comments));
In your parent file, add an event listener like this:
popup.addEventListener(ResultEvent.RESULT, processResult);
You should be able to get at your comments value as a property on the event:
protected function processResult(event:ResultEvent):void{
str=event.result
}
Another thing I've done as well is in the Child Container Create a public variable to pass the function from the parent ie:
in parent:
protected function captureComments(comments:String):void{
str=comments;
}
in child :
declare a public var and add the function to the save() function
public var parentFunction:Function;
private function save(): void{
if(comments == null){
comments = "";
}
parentFunction(comments);
Then when Creating your popup container in the parent:
protected function clickHandler(event:MouseEvent):void
{
popup = PopUpManager.createPopUp(this,pop,true) as pop;
popup.parentFunction = captureComments;
popup.close();
}

Flex 4 component on top of TitleWindow

I have Flex s:Group with some ui elements and I want it to be always (!) on top of any component inside my app, including s:TitleWindow (dialog).
How can I achieve it with Flex 4?
Thanks in advance!
You should use the mx.managers.PopUpManager class. It provides a simple interface to handle displaying content above any other.
You can write your own interface that encapsulates the PopUpManager interface to give you a chance to bring all your "always-on-top" components on top again, even when you add another popup that should appear behind.
Simple example:
public final class AlwaysOnTopPopUpManager {
private static var alwaysOnTopDisplayObjects:Array;
public static function addAlwaysOnTopObject(displayObject:IFlexDisplayObject):void
{
alwaysOnTopDisplayObjects = alwaysOnTopDisplayObjects || [];
if (alwaysOnTopDisplayObjects.indexOf(displayObject) == -1)
{
alwaysOnTopDisplayObjects.push(displayObject);
arrange();
}
}
public static function removeAlwaysOnTopObject(displayObject:IFlexDisplayObject):void
{
if (alwaysOnTopDisplayObjects)
{
var index:int = alwaysOnTopDisplayObjects.indexOf(displayObject);
if (index != -1)
{
alwaysOnTopDisplayObjects.splice(index, 1);
}
}
}
// uses the same interface as mx.managers.PopUpManager
public static function addPopUp(window:IFlexDisplayObject, parent:DisplayObject, modal:Boolean = false, childList:String = null, moduleFactory:IFlexModuleFactory = null):void
{
mx.managers.PopUpManager.addPopUp(window, parent, modal, childList, moduleFactory);
arrange();
}
private static function arrange():void
{
for each (var popup:IFlexDisplayObject in alwaysOnTopDisplayObjects)
{
mx.managers.PopUpManager.bringToFront(popup);
}
}
The class holds a list of objects to appear above any other content. Each time an object is added to that list or to the popups the arrange() method is called and bring all your registered objects to front again.
Add you top component in systemManager.rawChildren after application creationComplete event. See down:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
creationComplete="application_creationCompleteHandler(event)"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600">
<fx:Script>
<![CDATA[
import mx.core.UIComponent;
import mx.events.CloseEvent;
import mx.events.FlexEvent;
import mx.managers.PopUpManager;
protected function application_creationCompleteHandler(event:FlexEvent):void
{
panel.width = width;
panel.height = 300;
systemManager.rawChildren.addChild(panel);
}
protected function addPopup():void
{
PopUpManager.addPopUp(titleWin, this, true);
PopUpManager.centerPopUp(titleWin);
}
protected function button_clickHandler(event:MouseEvent):void
{
addPopup();
}
protected function titleWin_closeHandler(evt:CloseEvent):void
{
PopUpManager.removePopUp(evt.currentTarget as UIComponent);
}
]]>
</fx:Script>
<fx:Declarations>
<s:Panel id="panel" backgroundColor="0x00ff00" alpha="0.9" title="Panel">
<s:layout>
<s:VerticalLayout paddingLeft="50" horizontalAlign="left" verticalAlign="middle" />
</s:layout>
<s:Button id="btn" width="200" height="100" label="create popup"
click="button_clickHandler(event)" />
</s:Panel>
<s:TitleWindow id="titleWin"
title="Spark TitleWindow"
close="titleWin_closeHandler(event);"
width="300">
<s:layout>
<s:VerticalLayout paddingLeft="10" paddingRight="10"
paddingTop="10" paddingBottom="10" />
</s:layout>
<s:Label text="Popup window"
fontSize="24"
width="100%"/>
</s:TitleWindow>
</fx:Declarations>
</s:Application>
If all your elements are in the same MXML file, you simply have to put your s:Group element at the bottom of the file as the last element of it.
If your views are wired more dynamically, then you can force its index with something like this:
var topIndex:int = myParentView.numChildren - 1;
myParentView.setChildIndex(myGroupElement, topIndex);
Where myGroupElement if the reference to your s:Group or its ID.
myGroupElement must already be a child of myParentView when this code is executed.
If your s:Group element is only displayed occasionally, you might be interested in Popups.

Flex 4: State Change Event

Is there any event in Flex 4 that I can use to detect a state change?
I know this question is old but by googling for state change events I still get here so for people that want to know:
There is a StateChangeEvent.CURRENT_STATE_CHANGE event that is dispatched by the component, so your application can also listen for that.
In your listener function you can then acces the StateChangeEvent.oldState and StateChangeEvent.newState properties.
If you are talking about view states the answer is yes, you can listen for the enterState event like this (sorry for the simplicity of the example, it's part of a project I'm working on and I removed any relevant parts of the code):
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="800" minHeight="600"
currentState="loading">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
private function onEnterLoadingState():void{
Alert.show("Enter the loading state.", "Application");
}
private function onEnterLoginState():void{
Alert.show("Enter the login state.", "Application");
}
private function onEnterAddState():void{
Alert.show("Enter the addUser state.", "Application");
}
private function changeState(state:String):void{
currentState = state;
}
]]>
</fx:Script>
<s:states>
<s:State name="loading" enterState="onEnterLoadingState()"/>
<s:State name="login" enterState="onEnterLoginState()"/>
<s:State name="addUser" enterState="onEnterAddState()"/>
</s:states>
<s:Panel id="loadView" includeIn="loading" title="Loading">
<s:Button label="Go to login" click="changeState('login')"/>
</s:Panel>
<s:Panel id="loginView" includeIn="login" title="Login">
<s:Button label="Go to addUser" click="changeState('addUser')"/>
</s:Panel>
<s:Panel id="addView" includeIn="addUser" title="AddUser">
<s:Button label="Return to loading" click="changeState('loading')"/>
</s:Panel>
</s:Application>
And there is an exitState event in case you need it. I hope this helps you.
There are multiple state events you can listen for on any UIComponent class:
FlexEvent.STATE_CHANGE_COMPLETE
FlexEvent.STATE_CHANGE_INTERRUPTED
StateChangeEvent.CURRENT_STATE_CHANGING
StateChangeEvent.CURRENT_STATE_CHANGE
FlexEvent.ENTER_STATE
FlexEvent.EXIT_STATE
MXML:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
enterState="windowedapplication1_enterStateHandler(event)"
exitState="windowedapplication1_exitStateHandler(event)"
currentStateChange="windowedapplication1_currentStateChangeHandler(event)"
currentStateChanging="windowedapplication1_currentStateChangingHandler(event)"
stateChangeInterrupted="windowedapplication1_stateChangeInterruptedHandler(event)"
stateChangeComplete="windowedapplication1_stateChangeCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function windowedapplication1_stateChangeCompleteHandler(event:FlexEvent):void
{
}
protected function windowedapplication1_stateChangeInterruptedHandler(event:FlexEvent):void
{
}
protected function windowedapplication1_currentStateChangeHandler(event:StateChangeEvent):void
{
var oldState:String = event.oldState;
var newState:String = event.newState;
}
protected function windowedapplication1_currentStateChangingHandler(event:StateChangeEvent):void
{
var oldState:String = event.oldState;
var newState:String = event.newState;
}
protected function windowedapplication1_enterStateHandler(event:FlexEvent):void
{
}
protected function windowedapplication1_exitStateHandler(event:FlexEvent):void
{
}
]]>
</fx:Script>
</s:WindowedApplication>