AS3 Shortcut window and pop up - actionscript-3

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

Related

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.

Create Custom Dialog Box using dispatch events,states and titlewindow in flex/AS3.0

Since a month Iam working on creating a custom dialog box, having parameters like message,state and modal(true/false)
Eg:
showAlert("Hi, how are you doing","Goodmorning", true);
I have learned how to dispatch event. but unable to dispatch the alertevent/popupManager using States.
Below is the code, I am struggling with.
Main.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
public function onclick(event:MouseEvent):void
{
this.dispatchEvent("Hi, How are you?", "Morning", true);
}
public function dispatchEvent(arg1:String, arg2:String, arg3:Boolean):void
{
var str:*=null;
str.message = arg1;
str.stateName = arg2;
str.modal = arg3;
this.dispatchEvent(new ShowAlert(ShowAlert.SHOW, true));
}
]]>
</mx:Script>
<mx:Button id="click" click="onclick(event)"/>
</mx:Application>
ShowAlert.as
package
{
import flash.events.*;
public class ShowAlert extends Event
{
public var _stateName:String;
public var _closable:Boolean;
public var _message:String;
public var _isModal:Boolean;
public static const SHOW:String="show";
public function flash.events.(arg1:String, arg2:Boolean=false, arg3:Boolean=false)
{
super(arg1, arg2, arg3);
trace("arg1: "+arg1+"\t arg2: "+arg2+"\t arg3: "+arg3);
}
public function set message(arg1:String):void
{
this._message = arg1;
}
public function get message():String
{
return _message;
}
public function get modal():Boolean
{
return _isModal;
}
public function get stateName():String
{
return _stateName;
}
public function set stateName(arg1:String):void
{
this._stateName = arg1;
}
public function set modal(arg1:Boolean):void
{
this._isModal = arg1;
}
public override function clone():flash.events.Event
{
return new ShowAlert(type);
}
}
}
I was unable to write the custom titlewindow using states, so I dint post that.
Please let me know, how to make this happen.
Below is the Sample code, specifying my problem
main.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
public var info:IModuleInfo;
public var loadalert:DisplayObject;
import mx.modules.ModuleManager;
import mx.modules.IModuleInfo;
import mx.events.ModuleEvent;
public function init():void
{
Alert.show("This is forst alert.");
}
public function Loadalerrt():void
{
trace("loadalertmodule");
info = ModuleManager.getModule("../bin-debug/alerrtmod.swf");
info.addEventListener(ModuleEvent.READY, modEventHandler);
info.load();
}
public function modEventHandler(event:ModuleEvent):void
{
trace("modeventHandler");
loadalert=info.factory.create() as DisplayObject;
can1.addChild(loadalert);
}
]]>
</mx:Script>
<mx:Button label="Alert in Application" id="b1" click="init()" x="29" y="21"/>
<mx:Button label="Load Module" id="b2" click="Loadalerrt();" x="10" y="92"/>
<mx:Canvas id="can1" x="409" y="57" backgroundColor="cyan"/>
</mx:Application>
alerttmod.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400" height="300">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
public function alertshow():void
{
Alert.show("This is second alert, You Can see it covers whole application, What I want is its scope should be limited to this specific module, not to whole application ");
}
]]>
</mx:Script>
<mx:Button label="Alert in Module" id="b1" click="alertshow()" x="163" y="100"/>
</mx:Module>
Now I see your problem. I think it is not possible to restrict the modal area of the Alert. I can suggest you to fake the modal behaviour by desabling the modules elements while your dialog is being shown.
May be it can help you...
Here are two components to demonstrate it:
//your module with another Alert
<?xml version="1.0" encoding="utf-8"?>
<mx:Module xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="400" height="300">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.managers.PopUpManager;
public function alertshow():void
{
Alert.show("This is second alert...");
}
public function alertshow2():void
{
var customAlert:CustomAlert = new CustomAlert();
customAlert.addEventListener("CLOSED", onCustomAlertClosed);
this.enabled = false;
PopUpManager.addPopUp(customAlert, this, false);
PopUpManager.centerPopUp(customAlert);
}
private function onCustomAlertClosed(evt:Event):void
{
this.enabled = true;
}
]]>
</mx:Script>
<mx:Button label="Alert in Module" id="b1" click="alertshow()" x="163" y="100"/>
<mx:Button label="CustomAlert in Module" id="b2" click="alertshow2()" x="163" y="150"/>
<mx:Canvas width="100%" height="100%" backgroundColor="0xbbbbbb" alpha="0.8" visible="{!this.enabled}"/>
</mx:Module>
//simple CustomAlert as a Panel
<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="300" height="200">
<mx:Script>
<![CDATA[
import mx.managers.PopUpManager;
protected function button1_clickHandler(event:MouseEvent):void
{
PopUpManager.removePopUp(this);
this.dispatchEvent(new Event("CLOSED"));
}
]]>
</mx:Script>
<mx:Button x="112" y="128" label="Close" click="button1_clickHandler(event)"/>
</mx:Panel>

Alert and mouse & key events

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>