I was looking for a way to tell the app to confirm if you really want to close the app before losing the changes of the project.
Through the current API, I was not able to do it. Looking on how Air/Flex do that, it looks like an event listener of the window when closing:
<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"
maxHeight="1080"
maxWidth="1920"
minWidth="1280"
minHeight="720"
showStatusBar="false"
creationComplete="startUp()"
closing="closeWindow(event)"
>
when I close the window through the Window interface or through the application menu, it executed what I was expecting, a prompt before the window close
Do you want to exit the application?/Do you want to exit without saving changes?
yes no.
Do TideSDK/TideKIT have this behavior? if so, please attach an example. It is very important for me to understand how to do it properly.
Thanks.
This example helped me to do something similar in my TideSDK app:
https://gist.github.com/MisterPoppet/4639473
Pulling from the example there you may be able to do something like below to accomplish what you are asking:
var appWindow = Ti.UI.getCurrentWindow();
appWindow.addEventListener(Ti.CLOSE, function(event) {
var r = confirm("Do you want to exit the application?");
if (r == true) {
//close
} else {
//cancel close
event.preventDefault();
return false;
}
});
Related
I'm trying to implement a very simple way to select a subsection of the screen via mouse. The workflow is the standard one for many apps - click on starting point, move mouse and transparent rectangle updates between first point clicked and current position of the mouse. The basic code looks something like this (minus the graphics, which is simple)
<?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" mouseDown="application1_mouseDownHandler(event)">
<fx:Script>
<![CDATA[
import spark.components.mediaClasses.VolumeBar;
private var _anchorPoint:Point = new Point();
private var _currentPoint:Point = new Point();
protected function application1_mouseDownHandler(event:MouseEvent):void
{
addEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
addEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
_anchorPoint = new Point(event.stageX, event.stageY);
}
private function handleMouseMove(e:MouseEvent):void
{
_currentPoint.x = e.stageX;
_currentPoint.y = e.stageY;
trace("rectangle between (",_anchorPoint.x, ",", _anchorPoint.y, ") and (", _currentPoint.x, ",", _currentPoint.y, ").");
}
private function handleMouseUp(e:MouseEvent):void
{
removeEventListener(MouseEvent.MOUSE_MOVE, handleMouseMove);
removeEventListener(MouseEvent.MOUSE_UP, handleMouseUp);
}
]]>
</fx:Script>
</s:Application>
This breaks down when the user moves the mouse outside of the app. Not only _currentPoint stops updating, but also if you let go the mouse button outside of the app you miss the mouseUp event, i.e. when you move the mouse back on the app _currentPoint starts updating again as if you had never let go of the mouse button. Was wondering if there is a way in Flex (for web apps) to get around this by listening to mouseMove and mouseUp events when outside of the app (if that's possible) or whatever other way that may make sense.
thank you for your help!
Here's something most people don't know: MouseEvents are tracked outside of the application window if the MOUSE_DOWN event has been fired, but not MOUSE_UP. You can grab mouse positions outside of the application window (and even outside of the browser window) as long as whatever you're doing makes the user hold their mouse down. To test this, try running the following code:
<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"
creationComplete="init()">
<fx:Script>
<![CDATA[
protected function init():void {
addEventListener(Event.ADDED_TO_STAGE, magic)
}
protected function magic(e:Event):void {
stage.addEventListener(MouseEvent.MOUSE_MOVE, moreMagic);
}
protected function moreMagic(e:MouseEvent):void {
magicalButton.label = "Hold me down! " + String(e.stageX) + "x" + String(e.stageY);
}
]]>
</fx:Script>
<s:Button id="magicalButton" label="Hold me down!"/>
It might be possible with some hacking in AIR, but definitely not with a webapp opened in a browser.
Just imagine what would happen if websites could track your mouse outside the browser and be able to take screenshots of your OS!
Though this won't get you to where you want, you can make use of Event.MOUSE_LEAVE and MouseEvent.MOUSE_MOVE events to track whether the cursor is within the boundaries of the application.
I am playing multiple short video clips behind each other and I want it to look like it is one continuous video. Is there a way to stich them together so that it's unnoticable when you set a new video source.
At the moment I am having a problem where a black frame is inserted when I set a new video source. The order of events seems to be something like this
--> Video Finishes
--> Complete event dispatched
--> Set source to new video
--> Screen turns blank (this should not happen, instead it should keep the last frame of the video until the new video is loaded)
--> a few miliseconds pass
--> the new video starts playing.
Is it possible to avoid the screen turning blank or to keep the last frame showing until the next video is loaded.
Thanks,
Dennis
Technically, it is doable, however I doubt you'll be able to get this right 100% of the time. Here is how you'll need to do this.
Just before the first (or previous) video finishes, you'll have to load the next video in a new player instance. Of course depending a number of factors, how soon before the first finishes that you have to load the next depends on a number of factors
1. The bit rate of the next video
2. The Internet bandwidth of the client machine.
3. If the previous video has not loaded completely before you need to load the next, you'll have to account for that as well a not hamper the playing of the currently playing video.
4. Some client computers may not be able to do this without stuttering and glitches.
The best solution to the problem is to really stitch the videos together before hand. of course if you don't know the sequence before hand you can't do this, so you're left with doing what I mentioned earlier.
Here is the double video player that Shiv describes. This works for the most part, except for that there is a short pause when the next video loads... still not ideal.
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="400" height="300">
<fx:Metadata>
[Event(name="complete", type="org.osmf.events.TimeEvent")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import org.osmf.events.MediaPlayerStateChangeEvent;
import org.osmf.events.TimeEvent;
import org.osmf.media.MediaPlayer;
import org.osmf.media.MediaPlayerState;
import spark.components.VideoPlayer;
var _source:String = "";
var activePlayer:VideoDisplay = null;
var otherPlayer:VideoDisplay = null;
var playerIndex:int = 0;
public function set source (value:String) {
trace('set source: ' + value)
if(value == '' || value == null || value == _source) {
trace('rejected source');
return;
}
if(activePlayer != null) {
activePlayer.depth = 3;
}
activePlayer = getElementAt(playerIndex) as VideoDisplay;
playerIndex = playerIndex == 0?1:0;
otherPlayer = getElementAt(playerIndex) as VideoDisplay;
trace('active player: ' + activePlayer.id);
activePlayer.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, player1_mediaPlayerStateChangeHandler);
activePlayer.source = value;
_source = value;
}
public function get source ():String {
return _source;
}
protected function player1_mediaPlayerStateChangeHandler(event:MediaPlayerStateChangeEvent):void
{
trace('state change: ' + event.state + ', player: ' + (event.currentTarget.id));
if(event.state == MediaPlayerState.READY) {
player1.removeEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE,player1_mediaPlayerStateChangeHandler);
player2.removeEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE,player1_mediaPlayerStateChangeHandler);
activePlayer.play();
activePlayer.depth = 2;
otherPlayer.depth = 1;
}
}
protected function completeHandler(event:TimeEvent):void
{
if(event.currentTarget == activePlayer) {
trace('video complete');
dispatchEvent(event);
}
}
]]>
</fx:Script>
<s:VideoDisplay id="player1" autoRewind="false" complete="completeHandler(event)" autoPlay="true" opaqueBackground="false"/>
<s:VideoDisplay id="player2" complete="completeHandler(event)" autoRewind="false" autoPlay="true" opaqueBackground="false" />
</s:Group>
What TextInput event can I listen for to throw an Alert when a number is entered? The scenario is : a user enters a number into myTxt1. An Alert appears that says "Are you sure you want to enter that number?". If the user clicks Yes, do nothing/continue. If the user clicks No, leave focus on myTxt1 so he can change the number.
Problem is, I don't know what event to listen to to throw the Alert. I've tried valueCommit and focusOut. With both of these, the alert shows, but when the user clicks Yes, focus remains on myTxt1, even if the event was triggered by the user clicking on myTxt2. User tries to leave myTxt1, but sees the ALert, clicks Yes, focus remains on myTxt1, and it's a vicious cycle.
This seems like a simple issue, but I can't figure it out. Any advice?
If you are trying to prevent user from entering numbers or otherwise consider using restrict property. But if you just want user to be notified for entering number, you may use change event.
In your focusOut handler you have to store the object that is going to get the focus. That's because when you show an Alert this information is gone since the Alert window now gets the focus. See the following example on how to do it properly. I'd suggest you build your own custom component that does all the work for you...
<?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">
<fx:Script>
<![CDATA[
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.managers.FocusManager;
protected var previousValue:String;
protected var nextValue:String;
protected var focusInObject:InteractiveObject;
protected function isNumber(value:String):Boolean
{
// do your check
return true;
}
protected function textInput_focusOutHandler(event:FocusEvent):void
{
var value:String = TextInput(event.currentTarget).text;
if (!isNumber(value) || value == previousValue)
return;
nextValue = value;
focusInObject = event.relatedObject;
Alert.show("Are you sure you want to enter that number?", "", Alert.YES | Alert.NO, this, alertCloseHandler);
}
protected function alertCloseHandler(event:CloseEvent):void
{
if (event.detail == Alert.NO)
return;
previousValue = nextValue;
if (focusInObject)
systemManager.stage.focus = focusInObject;
}
]]>
</fx:Script>
<s:layout>
<s:VerticalLayout/>
</s:layout>
<s:TextInput focusOut="textInput_focusOutHandler(event)"/>
<s:CheckBox label="Foo"/>
<s:Button label="Bar"/>
</s:Application>
I've included a small optimization. The application remembers the value if the user presses Yes. In case you get another focusOut event and the value hasn't changed since last time then the Alert won't be shown.
You can listen for the change event if its a TextArea component. If there is any change in the text area then a change event will be fired. You can then check which key is pressed.
Below is my code, and the question is explained after it.
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:cal="cal.*"
layout="absolute"
applicationComplete="init()"
xmlns:geometry="com.degrafa.geometry.*"
xmlns:degrafa="com.degrafa.*"
xmlns:paint="com.degrafa.paint.*"
xmlns:containers="flexlib.containers.*"
xmlns:flexlib_controls="flexlib.controls.*"
xmlns:mdi_containers="flexlib.mdi.containers.*"
xmlns:auto="com.hillelcoren.components.*"
xmlns:local="*"
xmlns:components="CollapsibleAccordion.*"
modalTransparency="0.8"
modalTransparencyColor="0x000000"
backgroundSize="100%">
<mx:Script>
<![CDATA[
import c7.views.components.PhotoViewer.PhotoViewer;
import c7.config.ServerConfig;
import mx.core.Application;
import mx.containers.*;
import c7.models.GlobalModel;
private var pv_slideshow:PhotoViewer = null;
private function toggleFullScreen():void
{
if(stage.displayState == StageDisplayState.NORMAL)
{
this.pv_slideshow = new PhotoViewer;
Application.application.addChild(this.pv_slideshow); //added as top-most component to application itself
//set new sizes & go full-screen
this.pv_slideshow.x = 0;
this.pv_slideshow.y = 0;
this.pv_slideshow.width = stage.fullScreenWidth;
this.pv_slideshow.height = stage.fullScreenHeight;
try
{
stage.displayState = StageDisplayState.FULL_SCREEN;
}
catch(err:Error)
{
Alert.show(err.toString());
}
stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenEventHandler, false, 0, true); //intentionally weak referenced
//refresh the display sizes & display list
invalidateSize();
invalidateDisplayList();
}
/*else
stage.displayState = StageDisplayState.NORMAL;*/
}
private function fullScreenEventHandler(event:FullScreenEvent):void
{
if (event.fullScreen) //nothing to do in case when switching to full-screen
return;
//Alert.show(pv_slideshow.width.toString());
//application.removeChild(this.pv_slideshow);
Application.application.removeChild(pv_slideshow); //remove the full-screen container
this.pv_slideshow = null; //reset
//refresh the display sizes & display list
invalidateSize();
invalidateDisplayList();
}
The toggleFullScreen is fired on the click of a button... and it working absolutely fine. But the issue is in "exit" . When I click escape key fullScreenEventHandler is fired and it should remove the pv_slideshow.
This is where I get a null object reference error on the line:
Application.application.removeChild(pv_slideshow); //remove the full-screen container
I have tried using this.pv_slideshow and other such things.
Plz help me figure it out. what am i doing wrong and how should I make it work.
This is exact error message I get:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.core::Container/http://www.adobe.com/2006/flex/mx/internal::removingChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:3315]
at mx.core::Container/removeChild()[C:\autobuild\3.2.0\frameworks\projects\framework\src\mx\core\Container.as:2263]
at index_cloud/fullScreenEventHandler()[C:\development\flex_src\index_cloud.mxml:1661]
I wouldn't use Application.application either.
Please check first pv_slideshow really exists, you can get it's parent ( if has one ) and remove it later.
get the parent
pv_slideshow.parent
remove it from the parent_item
parent_item.removeChild( pv_slideshow )
Make sure also the version of Flex you are using, you may need to remove it with removeElement.
The intended architectural use of Application.application is not to use it as a uiComponent or displayObject, or whatever. If you're building a library project that is doing some calculations based on the application properties, or the application's systemManager, or you need access to the outter application from a loaded module, then you have good reason to use App.app.
You example is not one of those cases. Your best bet is to add your component to 'this' (as long as you're not going to use a "view" container), and do a this.removeChild. That should solve a good chunk of your issues.
Best of luck,
Jeremy
When I listen for key up and key down events with wmode="transparent", I receive 2 key down events followed by a single key up event for the following keys: F-keys, arrow keys, ins, del, home, end, page up, page down, pause, print screen, application key, windows key, and the equivalent numeric keypad keys. The other keys work normally. This is occurring with FF 3.5, but not with IE 6.
Below is a simple Flex application that illustrates the problem if you run it with wmode="transparent".
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" applicationComplete="init()">
<mx:Script>
<![CDATA[
import mx.controls.Label;
private function init():void {
stage.addEventListener(KeyboardEvent.KEY_DOWN, onKey);
stage.addEventListener(KeyboardEvent.KEY_UP, onKey);
}
private function onKey(event:KeyboardEvent):void {
var msg:Label = new Label();
msg.text = event.toString();
eventLog.addChildAt(msg, 0);
}
]]>
</mx:Script>
<mx:VBox width="100%" height="100%">
<mx:TextInput width="100%" text="Hello"/>
<mx:VBox id="eventLog" width="100%" height="100%"/>
</mx:VBox>
</mx:Application>
Our application requires wmode="transparent" and needs to handle both key up and key down events for the problematic keys, so I'm looking for the best way to solve this. What would be the best workaround for this problem? Is there some Flash player parameter that I can use to get this working? (FF configuration changes aren't viable for our application, but might be interesting for understanding the cause of this.)
By the way, the workaround I'm currently favoring is to discard additional key down events for a key during a brief dead-band (maybe 50-100 ms) following its initial key down event. This solution has the merits of being relatively simple to implement while still supporting key repeats, though with an additional delay before repeat begins.
Here's basically what I've added to the test code:
private var keyDownTs:Array = new Array();
private function onKey(event:KeyboardEvent):void {
var msg:Label = new Label();
msg.text = getTimer() + "-" + (isDead(event) ? "**DEAD**" : "") + event.toString();
eventLog.addChildAt(msg, 0);
}
private function isDead(event:KeyboardEvent):Boolean {
var dead:Boolean = false;
switch (event.type) {
case KeyboardEvent.KEY_DOWN:
var ts:int = keyDownTs[event.keyCode];
if (ts == 0) {
// save timestamp for the initial key down event
keyDownTs[event.keyCode] = getTimer();
} else if (getTimer() - ts < 50) {
// this key down is within the dead-band of the initial key down
dead = true;
}
break;
case KeyboardEvent.KEY_UP:
// clear previous key down timestamp
keyDownTs[event.keyCode] = 0;
break;
}
return dead;
}
On my system, the spurious key down events are happening within a few ms of the initial key down (2-6 ms), so 50 ms is looking like a pretty good value. For my production implementation, I think I'm going to put this logic into an EventDispatcher that KeyboardEvent listeners will use instead of listening to the stage directly.
I don't have an answer for you, but can confirm that wmode="transparent" has caused this exact same behaviour with an item on our website. Using transparent and opaque wmodes was causing this unidentified (until now) double keypress behaviour. Due to the numerous issues with opaque and transparent modes, we instead worked around all the other issues that surround using standard mode, because it's the only mode in which keyboard IO works correctly.
Other issues include incorrect key mappings, issues with screen-reading/accessibility software, flash movie does not start executing until it is scrolled into the viewport and others.
If there's any way you can survive without wmode transparent, then consider it, because otherwise, as far as I could see, everything is borked.
The reason we initially chose transparent mode was so we could overlay other HTML elements over the Flash movie. Now instead, if we're going to overlay, we "hide" the flash:
Don't use css display:none because this resets the movie (but not using AX version in IE).
The movie can be hidden by either setting its height to 0.001px via css or to visibility:hidden in css, or both.