Handling error conditions on Flex - apache-flex

I have the following AS code.I have noticed that if an Application i s using the webcamera then it cannot be used by any secondary applications until unless the primary application is closed.
My question is that from the following code 1.can we capture that condition
2.If no camera is detected how to give the alert since it is an AS code
EDIT:
Filename is cldAS.as
Now how to call cldAS() from any.mxml file .Some example would be appreciated
package org.com
{
import flash.display.Sprite;
import flash.media.*;
import flash.net.*;
public class cldAS extends Sprite
{
public function cldAS()
{
var cam:Camera = Camera.getCamera();
if(cam != null)
{
cam.setMode(640, 480, 30);
var video:Video = new Video(300, 450);
video.attachCamera(cam);
addChild(video);
}
else
{
trace("No Camera Detected");
//How to give an alert here
}
}
}
}

Alert.show("You don't seem to have a webcam.");
instead of
trace(...) ?

Alert is available in Flex only , in AS3 you should really implement your own solution, on the other hand , since Alert is a Javascript function , you could also use ExternalInterface to call it.
As far as implementing your own solution is concerned, at the minimum you need a TextField to display your message, which text you could provide by sending a CustomEvent with a message property that will simply take a String. It wouldn't take too much work to create your own Alert class.It would sit on top of your App , you could toggle visibility when receiving a CustomEvent and have a Close button to hide it.
You should be able to call your AS3 class within script tags , other than that I'll leave a more detailed answer to Flex experts. I'm not sure if you can add a Sprite directly into Flex , for all I remember an object in Flex must inherit from UIComponent in order to be added to the stage but check with the other guys here, I haven't used Flex in quite some time...
<mx:Script>
import org.com.cldAS;
public cld:cldAS = new cldAS();
</mx:Script>

Related

how to find height of dynamic flex component used as a popup

I've created a custom component with several inline item renderers that I use as a tooltip. The height of the component is unknown, as the data contents of the component are not known until runtime.
However, when displaying the tooltip, occasionally it extends beyond the boundaries of the flash application, thus, I'd like to be able to detect this occurrence and reposition the tip.
The problem is that the height and width of the component are, apparently, not available until after being rendered by the popup manager. (i.e. they are always 0)
But, I do not know any way of finding out when the popup is actually rendered and, therefore, the height/width values available.
I tried adding a resize event listener to the component, but it doesn't appear to work, though I most certainly could be doing something wrong since it seems to me that the resize event only gives you the "oldWidth" and "oldHeight" of the object, which, at first display, would be 0...and useless to me.
Any ideas about how to proceed?
-----Edit-----
I have a base class like this:
public class TTComponent extends Canvas
{
var _parentC:UIComponent;
var popped:Boolean = false;
var timer:Timer;
var _comp:UIComponent;
public function set parentComponent(pC:UIComponent):void
{
_parentC = pc;
_parentC.addEventListener(MouseEvent.MOUSE_OUT, mouseOut);
_parentC.addEventListener(MouseEvent.MOUSE_OVER, mouseOver);
}
public function mouseOver(evt:MouseEvent):void
{
if (_parentC != null)
{
timer = new Timer(150,1);
_comp = this;
timer.addEventListener(TimerEvent.TIMER_COMPLETE, function( tevt:TimerEvent ):void
{
this.move( somex, somey);
if (popped != true)
{
PopUpManager.addPopUp(_comp, parentComponent );
popped = true;
});
timer.start();
}
}
public function mouseOut(evt:MouseEvent ):void
{
if ( timer )
{
timer.stop();
timer = null;
}
//If we popped up, remove the popup
if ( popped )
{
PopUpManager.removePopUp( _comp );
popped = false;
parentC .removeEventListener(MouseEvent.MOUSE_OUT, mouseOut);
parentC .removeEventListener(MouseEvent.MOUSE_OVER, mouseOver);
}
}
}
Then, an extended renderer like this:
<c:TTComponent name="T" xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:c="components.*">
<s:BorderContainer>
...about 30 labels grouped in various manners
...2 lists with inline item renderers
</s:BorderContainer>
</c:TTComponent>
Now, the code is called like this:
var w = new TTComponent();
w.data = data;
win.parentComponent = this;
This will add listeners to the mouse over and mouse out events on the parent, whatever it is, and then show or hide the tooltip accordingly.
------Edit------
Using a portion of what a commenter below suggested, this is the solution I came up with:
Inside the TTComponent class:
import flash.events.Event;
import mx.binding.utils.ChangeWatcher;
private var heightWatcher:ChangeWatcher;
public function set parentComponent
{
...
heightWatcher = ChangeWatcher.watch(this,'height',onSizeChange);
}
public function onSizeChange(evt:Event):void
{
if (this.height != 0)
{
....calculate the new component coords
this.move(newx, newy);
}
}
Note that this additional code doesn't bind to any component variable, it just adds a watcher on the component property.
You could also try binding your width and height. If these are made bindable in your class, flex will automatically adjust your popup's width and height.
When using mxml for your binding, you can just do something like this
<mx:YourComponent height="{HeightOfYourTooltip}" width="{WidthOfYourTooltip}"></mx:YourComponent>
You can also add a eventListener that listens to the change event if you want to reposition you component, like so
<mx:YourComponent height="{HeightOfYourTooltip}" width="{WidthOfYourTooltip}" change="yourComponentResizeHandler()"></mx:YourComponent>
If you are using a programmed approach, you should should use the changewatcher. Below is shown how you can use that.
ChangeWatcher.watch(YourComponent, "width", repositionHandler);
ChangeWatcher.watch(YourComponent, "height", repositionHandler);
If you want to watch for other variables or properties to change, be sure to add the [Bindable]-tag above your variables in your class, like this
[Bindable]
var myVariable:SomeVariable;
I hope this helps.
For displaying toolTip which controls you are using in itemRenderer? Text or Label?
Try to Listen update complete Event of that component. May this Help you. :)
This might be messy, but on the pop up component, you could add an event listener after complete is fired, if the height or width == 0 then you setTimeout() to a function after say 100ms until you get valid data.
Yes, I know it is a bit of a hack, but those will eventually report correctly measured values so it's not going to call that many times.
Just an idea if you are against a deadline or something like this isn't critical. :)

Flex Type Ahead DropDownList

I need to implement multi character type ahead functionality on a DropDownList. Im using spark components Flex 4.5.1.
I wish the long list to for example if I type bl
It will go to Blue not to the first B then the first L
Its a common requirement and all browsers now support it, hope its something that already exists or someone has customized a version.
Why wouldn't you use the Flex Spark ComboBox, which has the type ahead feature built right in?
You can probably customize one of the many autocompletes. I posted the following snippet in another question on how to do an autocomplete.
package autoCompleteExample
{
import mx.collections.ICollectionView;
import mx.collections.IList;
import spark.components.ComboBox;
import spark.events.TextOperationEvent;
public class AutoCompleteExample extends ComboBox
{
override protected function textInput_changeHandler(event:TextOperationEvent):void{
super.textInput_changeHandler(event);
ICollectionView(dataProvider).refresh();
}
override public function set dataProvider(value:IList):void{
ICollectionView(value).filterFunction = defaultFilterFunction;
super.dataProvider = value;
}
private function defaultFilterFunction(item:Object):Boolean{
return (textInput.text.toLowerCase() == String(item[labelField].toLowerCase()).substr( 0, textInput.text.length ));
}
}
}
You can probably just change the text operation handler to select the first item AFTER the refresh. Not sure how well it would work.

unable to get focus on canvas

I am creating a canvas in actionscript like :
private var cvs_preview:Canvas = null;
private function show_preview():void
{
this.cvs_preview = new Canvas();
this.cvs_preview.id = "cvs_preview_1";
this.cvs_preview.setStyle('backgroundColor', 0x000000);
this.cvs_preview.setStyle('backgroundAlpha', 1);
this.cvs_preview.setStyle('borderColor', 0x417FDD);
this.cvs_preview.setStyle('cornerRadius', 10);
this.cvs_preview.setStyle('borderStyle', 'solid');
this.cvs_preview.setStyle('dropShadowEnabled', true);
var pt:Point = image.localToGlobal(new Point(image.x, image.y));
this.cvs_preview.x = pt.x - 50;
this.cvs_preview.y = pt.y - 50;
this.cvs_preview.height = 200;
this.cvs_preview.width = 250;
//this.cvs_preview.addEventListener(FlexEvent.CREATION_COMPLETE, get_focus_on_canvas);
//this.cvs_preview.focusManager.setFocus(
//this.cvs_preview.addEventListener(MouseEvent.CLICK, end_preview_on_focus_change);
this.cvs_preview.addEventListener(FocusEvent.MOUSE_FOCUS_CHANGE, end_preview_on_focus_change);
Application.application.addChild(this.cvs_preview); //add as top-most visible container
btn_mini_preview.enabled = false;
}
So on the focus change i want to run the "end_preview_on_focus_change()"
but this is not working.
As per my understanding, i think the canvas not getting any focus in the first place. I was trying to use focusManager.setFocus to do that after the canvas's creation complete. but even that is giving me an error.
the code i was trying on Creation.Complete is :
private function get_focus_on_canvas(e:FlexEvent)
{
focusManager.setFocus(e.target);
//Alert.show("testing img complete");
}
this is giving me an error "1118: Implicit coercion of a value with static type Object to a possibly unrelated type mx.managers:IFocusManagerComponent."
basically i just want to use the focus out event of the canvas.
Can someone help me with this...
I have been on this issue since a long time.
Regards
Zeeshan
The error is correct. You have an object of type Object which you are trying to use as an IFocusManagerComponent. This will not work. To accomplish that line of code, you need to do something like
focusManager.setFocus( IFocusManagerComponent( e.target ) );
This, of course, assumes that the target implements IFocusManagerComponent. It will give you an error otherwise (and likely will in this case because Canvas is not listed as an IFocusManagerComponent). The good news is that Canvas does have a drawFocus method which will accomplish the same thing.
As to your MOUSE_FOCUS_CHANGE event, that will only be fired if an object already HAS focus and then loses it. I think you are better off using FlexEvent.CREATION_COMPLETE. This will ensure that the component has registered itself with all of the appropriate classes in the Flex SDK so that the FocusManager can even be aware of the new object. Whatever you do, do not try to set focus on something which has not been added to the stage (ie: Event.ADDED has been called).
As another piece of advice -- Event.ADDED bubbles, make sure that event.currentTarget == event.target to make sure that you are listening to the correct object. Otherwise, you might be calling the same function multiple times erroneously.
Only a few classes implement IFocusManagerComponent as others mentioned and Canvas is not one of them. If you really must call FocusManager.setFocus() you will have to extend the canvas class to implement this interface and use that class instead. You don't have to write any methods to implement this interface, all methods have already been implemented by UIComponent itself
//FocusableCanvas.as (include appropriate package and import statements)
public class FocusableCanvas extends Canvas implements IFocusManagerComponent
{
public function FocusableCanvas()
{
super();
}
}
//Now use this class instead of Canvas
this.cvs_preview = new FocusableCanvas();
//setFocus in creation complete handler
FocusManager.setFocus(IFocusManagerComponent(e.target));
But if all you want to do is to set focus on the canvas upon it's creation, you can call canvas.setFocus() from the creationComplete handler instead.
private function get_focus_on_canvas(e:FlexEvent)
{
Canvas(e.currentTarget).setFocus();
trace("done");
}
I see two problems, and no perfect solutions. With any luck, this can help you out.
First of all, e.target returns an object typecast with type Object. This explains your implict coercion error, because Object does not implement IFocusManagerComponent.
Second, iFocusManagerComponent is only implemented by Accordion, AdvancedListBase, Button, ButtonBar, ChartBase, ComboBase, DateChooser, DateField, HTML, ListBase, MenuBar, NumericStepper, TabNavigator, TextArea, TextInput, UIMovieClip as per this entry in the Flex 3.4 AS3 Reference.
This leads me to believe that a Canvas element cannot take focus and has simply inherited access to the FocusManager through inheritance of UIComponent.
The only solutions I can see are to utilize something other than Canvas to handle your focus related concerns, or subclass Canvas and implement iFocusManagerComponent, though that looks fairly complex.
Edit
Apologies for missing drawFocus in the above solution.
Please try;
private function get_focus_on_canvas(e:FlexEvent)
{
this.cvs_preview.setFocus();
}

How to raise an event from a SWF in a SWFLoader to a parent Flex application?

How can I raise an event from a SWF file loaded into a Flex application (using SWFLoader)?
I want to be able to detect
a) when a button is pressed
b) when the animation ends
You'll need to do 2 things:
Dispatch an event from the loaded swf. Make sure the event bubbles if you sent it from nested views. Bubbling can be set through the bubbles property of the event.
Listen to the event from your main application. I think you should be able to do that on the content property of the SWFLoader instance.
mySWFLoader.content.addEventListener("myEvent", myEventHandler);
I took a lazier approach for raising the event inside flash
Flex:
<mx:SWFLoader source="homeanimations/tired.swf" id="swfTired" complete="swfTiredLoaded(event)" />
private function swfTiredLoaded(event:Event): void {
mySWFLoader.content.addEventListener("continueClicked", continueClickedHandler);
}
Flash:
dispatchEvent(new Event("continueClicked", true, true));
I believe its because you would be creating two seperate custom event class one in Flash and the other in Flex.
Dispatching one EV_NOTIFY.ANIMATION_ENDED from Flash may not be understood by Flex,since it has its own version of EV_NOTIFY.ANIMATION_ENDED.
As an adjunct to the answer by Christophe Herreman, and in case you were wondering, here is a way of making your own events...
package yourpackage.events
{
import flash.events.Event;
[Event(name="EV_Notify", type="yourpackage.events.EV_Notify")]
public class EV_Notify extends Event
{
public function EV_Notify(bubbles:Boolean=true, cancelable:Boolean=false)
{
super("EV_Notify", bubbles, cancelable);
}
}
}
I have taken the liberty of setting the default value of bubbles to true and passing the custom event type to the super constructor by default, so you can then just say...
dispatchEvent(new EV_Notify());
In your particular case I doubt there are times when you would not want your event to bubble.
The prefix EV_ on the name is my own convention for events so I can easily find them in the code completion popups, you'll obviously pick your own name.
For the two cases you cite you can either have two events and listen for both of them, or add a property to the event which says what just happened, which is the approach which is taken by controls like Alert...
package yourpackage.events
{
import flash.events.Event;
[Event(name="EV_Notify", type="yourpackage.events.EV_Notify")]
public class EV_Notify extends Event
{
public static var BUTTON_PRESSED:int = 1;
public static var ANIMATION_ENDED:int = 2;
public var whatHappened:int;
public function EV_Notify(whatHappened:int, bubbles:Boolean=true, cancelable:Boolean=false)
{
this.whatHappened = whatHappened;
super("EV_Notify", bubbles, cancelable);
}
}
}
then you call it as follows...
dispatchEvent(new EV_Notify(EV_NOTIFY.ANIMATION_ENDED));
you can then inspect the whatHappened field in your event handler.
private function handleNotify(ev:EV_Notify):void
{
if (ev.whatHappened == EV_Notify.ANIMATION_ENDED)
{
// do something
}
else if (ev.whatHappened == EV_Notify.BUTTON_PRESSED)
{
// do something else
}
etc...
}
HTH
I could not make this last approach work (with Flash CS4 and Flex 3). I put the dispatchEvent call in one of the last frames of my Flash animation, but could not pick it up in Flex.
I resorted to a counter variable and incrementing until I reached the known last frame number using the ENTER_FRAME event - which I can pick up using almost the same code.
If I can pick this up, then why can't I pick up a custom event?

Flash TextField HTML - How do I prevent the error dialogue for missing images? (Error #2044: Unhandled IOErrorEvent:. text=Error #2035: URL Not Found)

I'm using a Flash TextField control to display some HTML content inside a Flash presentation to be shown on a large touch-screen kiosk. Unfortunately, if any image tag in the displayed HTML content points to a non-existent image, a dialogue is shown with the error message
Error #2044: Unhandled IOErrorEvent:. text=Error #2035: URL Not Found.
I am trying to avoid having that dialogue pop up. The solution for loading content through a loader class is to catch IOErrorEvent.IO_ERROR, but I've tried listening for that on the TextField, on stage, Main and loaderInfo to no avail. I've tried wrapping the whole thing in a try-catch, and that also doesn't work.
Here's the simplified code I'm using to find solutions:
package {
import flash.display.Sprite;
import flash.errors.IOError;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
public class Main extends Sprite {
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
var html:TextField = new TextField();
html.type = TextFieldType.DYNAMIC;
html.multiline = true;
html.htmlText = "Bogus image: <img src=\"foo.jpg\" />";
addChild(html);
}
}
}
Edit: And here's the entire working code.
For dynamic content and so forth, of course, you would need a list of images and a function to generate handlers, etc.
package {
import flash.display.Loader;
import flash.display.Sprite;
import flash.errors.IOError;
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
public class Main extends Sprite {
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
var html:TextField = new TextField();
html.type = TextFieldType.DYNAMIC;
html.multiline = true;
html.htmlText = "Bogus image: <img id=\"image\" src=\"foo.jpg\" />";
var loader:Loader = html.getImageReference("image") as Loader;
if(loader){
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, function(e:Event):void {
trace("Error loading foo.jpg!");
});
}
addChild(html);
}
}
}
You can add ID's to images
html.htmlText = "Bogus image: <img src=\"foo.jpg\" id="image" />";
And then setup IOErrorEvent handler to each image in HTML
var loader:Loader = html.getImageReference("image") as Loader;
if(loader){
loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, function(e:Event):void{});
}
This is a cool problem.
I have two suggestions.
1) Don't use TextField. I'm guessing that you developed in Flash before Flex, like me. You may already know this, but it took me awhile to find out: The TextField object isn't meant to be used for regular use in Flex. Check this out from the Flex3 language ref:
The TextField class is used to create
display objects for text display and
input. All dynamic and input text
fields in a SWF file are instances of
the TextField class. You can use the
TextField class to perform low-level
text rendering. However, in Flex, you
typically use the Label, Text,
TextArea, and TextInput controls to
process text.
Obviously, there's nothing wrong with using TextField, but I've found that when I'm trying to figure out tricky problems, it's really helpful to do as much 'by the book' as I can to remove unknowns (as much as possible, at least).
2) I think I'd try either extending the Text component, or else creating a new component based on Text. In this component I'd add logic to load and insert images into the TextField object. That way, you could easily build and validate the string to insert into the TextField object prior to inserting it into the TextField.
If you get this working, please post - I could use it myself. :)
If there's a way for you to use the new FTE/TLF components, do so. Adobe is basically turning its back on the old TextField API, and this same error is a reason that I had to abandon many projects and components in the past. This error is thrown and basically cannot be caught. One of the worst aspects of Flash work in my opinion.
TLF addresses these problems and is SO much easier to work with. What would take days of experimentation in the old API now takes only a few hours. I've built a few rich text editors on the new API and it is SO very nice to use. You'll be glad you did :)
I was able to detect when an image has loaded, but I think I'll follow the TLF advice. anyways if you need to know, you have to implement an enter_frame event listener on the Loader and check for the contentInfo on the bytes property the Lenght, if the image hasn't load the length is 0xffffffff, if the image has loaded the length is the size of the file, and if there is an error the bytes properties es NULL.
var html:TextField = new TextField();
html.width=388.95;
html.height=400;
html.type = TextFieldType.DYNAMIC;
html.multiline = true;
html.htmlText = "Bogus image: <img id='image' src='foo.jpg'/>";
var loader:Loader = html.getImageReference("image") as Loader;
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHan);
function completeHan(e:Event){
addChild(html);
}
This will work..
This is a problem I'm also dealing with: it's a real annoyance. I'd really like to be able to catch all the errors. I assumed you could say...
stage.addEventListener(IOError.IO_ERROR, myErrorHandler);
...but that doesn't seem to work, as you've pointed out.
Perhaps you can check to make sure the kiosk's flash player isn't the debug version. I don't think that the release version throws the dialogs (could be wrong).
Impossible! Same problem if you use the Loader to load images that doesnt exists! Flex is a framework and the Image class uses this flash Loader object but with plenty of lines of code (check out the source of SwfLoader...).
You can check your image URL before set the htmlText property or you can create your own component to display Text and Images..
I can't believe this simple & stupid bug is not still fixed by Adobe!

Resources