Actionscript - Event That Notifies When Image Source Has Changed AND is Done Loading - actionscript-3

I am looking for an event that fires after an image's source property has been changed, and the image display object has loaded the new data. I thought the 'complete' event was the way to go, but it seems to fires as soon as the source has changed, BUT before the image is done loading. In the snippet below, I am trying to get the imgMap_completeHandler to fire once imgMap has been updated with the bytes from doExport().
public function doExport(bytes:ByteArray):void
{
FlexGlobals.topLevelApplication.addElement(this);
imgMap.source = bytes;
}
protected function imgMap_completeHandler(event:Event):void
{
var pngEncoder:PNGEncoder = new PNGEncoder();
var snapShot:ImageSnapshot = ImageSnapshot.captureImage(this,0,pngEncoder);
export = snapShot.data;
dispatchEvent(new Event("exportComplete"));
}
<s:Image id="imgMap" complete="imgMap_completeHandler(event)" width="100%" height="100%"/>

Have you tried to extend Image class and source method to do that?
You may only have to create a standard event just after the
public function source(....)
{
[super source...]
dispatchEvent(new Event('Loaded'));
}
Hope it helps!

Related

How to load a swf and interact with it?

I have tried SWFLoader, but the problem is the loaded content is MovieClip and I don't know how to interact with it, and the MovieClip#numChildren is zero.
And by the way, I can't pass the flashvars to the swf.
Firstly, you should know that there is no exact answer to your question as it depends on your loaded SWF (you know it or not, its display list, ...) but I'll put a simple example to explain things and you have to adapt it to your case.
For this example, let's say that we have a very simple SWF (the loaded SWF) which contain a TextField (called txt_url) and a button (a MovieClip, called btn_go).
The btn_go button will open the URL entered in the txt_url TextField.
For our second SWF (the loader), we will use a Loader object to load our first one (which is in this case will be the Loader.content) and then we will set the URL (the txt_url text) and trigger the click event on the btn_go button.
So here is an example of the code of our loader.swf :
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, on_SWFLoad);
loader.load(new URLRequest('loaded.swf'));
addChild(loader);
function on_SWFLoad(e:Event): void
{
// get our loaded SWF
var loaded_swf:DisplayObjectContainer = DisplayObjectContainer(loader.content);
// because we know our target objects, we can use "getChildByName()"
// set the URL
TextField(loaded_swf.getChildByName('txt_url')).text = 'http://www.example.com';
// open the URL in the browser by triggering the click event on the "btn_go" button
MovieClip(loaded_swf.getChildByName('btn_go')).dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
This example will directly set and open the URL in the browser after loading the SWF, of course we can execute that action after clicking a button or something else but it's just a simple example to show you how you can do ...
Now, the problem is when we don't know anything about the loaded SWF and its children (names, depths, ...), in this case we should do more effort to do what we want : we should traverse the entire display list of the loaded SWF to identify the target objects.
Returning to our example and let's say that we only know that there are a TextField and a button in the stage, so our code can be like this for example :
function on_SWFLoad(e:Event): void
{
var loaded_swf:DisplayObjectContainer = DisplayObjectContainer(loader.content);
var num_children:int = loaded_swf.numChildren;
for(var i:int = 0; i < num_children; i++)
{
var child:DisplayObject = loaded_swf.getChildAt(i);
if(child is TextField)
{
trace(child.name); // gives : txt_url
TextField(child).text = 'http://www.example.com';
}
else
{
if(child.hasEventListener(MouseEvent.CLICK))
{
trace(child.name); // gives : btn_go
child.dispatchEvent(new MouseEvent(MouseEvent.CLICK));
}
}
}
}
Again, it's a very simple example just to show how we can proceed ...
...
Then about passing values (params) between SWFs, take a look on my answer of this question where you have a little example for that.
For more about Display programming (display list, display object, display object container, ...) take a look here.
Hope that can help.

Change a variable on click actionscript

I would like to know how I could change a variable on click using actionscript.
I have :
private var test:int = 0;
public function thisIsTest():void{
test = test + 1;
}
<mx:Image left="10" bottom="10" source="#Embed(source='Assets/blabla.png')" click="thisIsTest()" buttonMode="true"/>
I would like to add 1 to the variable test each time I click on the button 'blabla'.
The problem is that it only works once.
Thank you for your help
The simplest method would be to use a MouseEvent listener. You attach the listener to whatever you want to be clicked and tell the listener which function to execute when an event is triggered:
var test:int = 0;
image.addEventListener(MouseEvent.CLICK, thisIsTest);
// Will 'listen' for mouse clicks on image and execute thisIsTest when a click happens
public function thisIsTest(e:MouseEvent):void
{
test = test + 1;
trace(test);
}
// Output on subsequent clicks
// 1
// 2
// 3
// 4
This does mean the image you want to attach the listener to needs to be a display object, like a sprite or movieclip, but this shouldn't be a problem if you're using Flash.
EDIT: Further actions noted in comments.
Import an image into Flash and use it to generate a Sprite or Movieclip and give it an Actionscript link id (like a class name):
// Add the image to the stage
var img:myImage = new myImage();
addChild(img);
// Assign the mouse event listener to the image
img.addEventListener(MouseEvent.CLICK, thisIsTest);

Custom Event from Item Renderer not detected by a class

I am trying to dispatch a custom event from an item renderer(which is a child of the Main application file / root).
Code in Main.mxml:
<s:List id="movieGrid"itemRenderer="views.MovieRenderer" dataProvider="{new ArrayCollection()}">
</s:List>
<s:Group width="100%" height="100%" bottom="60">
<views:DetailedViewInfo id="detailed" includeIn="MoviePage" />
</s:Group>
Renderer (something clicked):
MyEventDispatcher.Dispatcher.dispatchEvent(new MovieClickEvent(MovieClickEvent.CLICKED, data));
DetailedViewInfo (creation complete):
MyEventDispatcher.Dispatcher.addEventListener(MovieClickEvent.CLICKED, clickHandler);
MyEventDispatcher:
package events
{
import flash.events.EventDispatcher;
public class MyEventDispatcher
{
public static var Dispatcher:EventDispatcher = new EventDispatcher();
}
}
Event:
package events
{
import flash.events.Event;
public class MovieClickEvent extends Event
{
public function MovieClickEvent(type:String, theMovieData:Object, bubbles:Boolean=true, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
this._result = theMovieData;
}
public function get result():Object
{
return this._result;
}
override public function clone():Event
{
return new MovieClickEvent(type, result, bubbles, cancelable)
}
public static const CLICKED:String = "MovieClickEvent.CLICKED";
private var _result:Object;
}
}
I am able to listen for the event successfully in the Main.mxml but I also need to detect it in a SkinnableContainer - "DetailedViewInfo" that is also a child of Main.mxml:
It his possible at all? I tried importing all related events / classes and same for declarations. It does not work even if I comment out the event listener in Main.mxml. I tried adding a declaration to the item renderer in DetailedViewInfo but that crashes the application with no understandable error.
Could someone explain to me how this should be done? I am using custom events all over the place in my application and hadn't had this happen before. Any help highly appreciated!
It would seem you're adding the event listener after the event was dispatched. I see you have an includeIn statement there: this means the DetailedViewInfo component will not be immediately created, but only when the MoviePage state is entered. The event may be dispatched before the component is created and the event listener attached.
The quick fix for this issue, is to not use includeIn, but set the component's visibility according to the current state:
<views:DetailedViewInfo id="detailed" visible="false" includeInLayout="false"
visible.MoviePage="true" includeInLayout.MoviePage="true" />
However, you may want to review your architecture if you need to resort to this. Unfortunately I can't tell you much more than that, since I don't know your current architecture.

Action Script 3 new loader

I was revisiting some code for a simple picture viewer that I created in Action Script 2.0 now taking on the same task in AS3. At present i'm well aware that the command .loadMovie is no longer used. After numerous attempts to find a solution I have come up dry.
At the moment I have a movie clip symbol(target_mc) on the stage that I want to load jpegs from a external file when I mouseOver a button. Can any one give a example of how this should be approached using the "new load" variable.In the AS2 version i also used (on release) in the button code.
training_btn is the button instance.
Please see an example of my code below:
training_btn.addEventListener(MouseEvent.CLICK, imageOver);
function imageOver(evt:MouseEvent) {
this.target_mc.loadMovie("galleryimage/p_traininglink.jpg")
}
Any ideas would be very helpful.
Wayne
Here at the Republic of Code is an excellent step-by-step tutorial on how to work with the loader class in as3
Yeap
training_btn.addEventListener (MouseEvent.MOUSE_UP, onMouseUp);
function onMouseUp (evt:MouseEvent):void {
var my_loader:Loader = new Loader();
my_loader.load(new URLRequest("myPhoto.jpg"));
target_mc.addChild(my_loader);
}
So, basically the whole structure of the laoder has change between AS 2 and 3.
Now you need to create a different object that loads the content.
var loader:Loader = new Loader();
Than you can do two things:
Add event listener and than trigger the load
Trigger the load and add the loader to the stage
The difference between these two style is big, the first one will add a listener and wait for the load to complete and after that it will call a method you define in the listener to do any further instuctions.
The second one starts loading the content and adds the loader to the display list so that when the content is loaded it automatically displays.
1.
// add the listener
laoder.contentLoaderInfo.addEventListener( Event.Complete, onLoadComplete );
// trigger the load (remember: the url is alwais a URLRequest object)
loader.load( new URLRequest("path_to_file") );
// additional var for storing the content (only the content, without the loader)
var content:Bitmap;
function onLoadComplete( e:Event ):void{
content = e.target.content as Bitmap;
// you could use also:
// content = loader.content as Bitmap;
// you can do some modifications before displaying the content
// and finally add it to the display list
this.target_mc.addChild( content );
}
2)
// trigger the load (remember: the url is alwais a URLRequest object)
loader.load( new URLRequest("path_to_file") );
this.target_mc.addChild( loader );
The two ways are correct but I prefer using the first one cause it gives you more controll. You can also check out the progress of loading by listening to the ProgressEvent.PROGRESS.
link: Loader Documentation
link: URLRequest Documentation
Hope it helps. Search in google for more info about loading external data, there's a lot of resource about that.
It would probably best to create a Class that would handle all of this, but to answer your question, your code would look something like:
var outLoader:Loader = new Loader();
outLoader.load(new URLRequest("outImage.jpg"));
var overLoader:Loader = new Loader();
overLoader.load(new URLRequest("overImage.jpg"));
overLoader.visible = false;
var training_btn:Sprite = new Sprite();
training_btn.addChild(outLoader);
training_btn.addChild(overLoader);
training_btn.buttonMode = true;
training_btn.mouseChildren = false;
training_btn.addEventListener(MouseEvent.ROLL_OVER, rollOverHandler);
training_btn.addEventListener(MouseEvent.ROLL_OUT, rollOutHandler);
addChild(training_btn);
function rollOverHandler(e:MouseEvent):void {
overLoader.visible = true;
}
function rollOutHandler(e:MouseEvent):void {
overLoader.visible = false;
}

calling function in a runtime loaded swf

Using AS3 / Flash CS4
Alright thanks to everyone who is reading this. My problem specifically I am designing a user interface with controls on it. 5 buttons rotate left, rotate right, zoom in, zoom out, and auto rotate. The interface in itself works fine, I can trace out button clicks, toggle the auto rotate button etc...
My program reads an xml file. Loads some images, fills an array with links for each image, and when the image is clicked a loader loads a swf from a URL and displays it on screen. No problem.
Now I originally had the zoom controls user interface in the runtime_loaded.fla library, and the mouse listeners in the same linked document class. The interface works with the movieClip in runtime_loaded.swf when it is in the same code.
Now to practice good coding, I decided to remove the UI from the runtime_loaded.fla and add it to the Main.fla. This is essential because the main is going to handle possible 100's of images/objects that each have their own unique swf to link too. If I decide to change out the look of the interface but leave the function calls the same, I could essentially put in as many as I want into the main.fla instead of the runtime_loaded.fla which I would have to do for every single object.
THE FILE STRUCTURE
Main.fla <- interface in the library. 5 mouse event functions. Inside each function calls
a property of loaded_swf (loaded_swf.rotateLeft, loaded_swf.rotateRight) etc...
Runtime_loaded.fla <- links specificObject.as in properties (AS3/CS4)
specificObject.as <- has 5 public static functions{ rotateRight, rotateLeft, zoomIn, zoomOut, toggleAutoRotate }
THE CODE
//showFlashBox
function showFlashBox(temp_string:String):void {
if(!flash_box_on){
var temp_top:uint = numChildren;
addChildAt(FlashBoxContainer,temp_top);
newXButton.addEventListener(MouseEvent.CLICK, flashBoxXClick);
1. addChild(new_loader);
2. var url:URLRequest = new URLRequest(temp_string);
new_loader.x = 0;
new_loader.y = 0;
new_loader.load(url);
3. new_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, gotSwf);
flash_box_on = true;
}
}
function gotSwf(e:Event){
4. //loaded_swf = e.target.content;
trace(e.target.content);
5. new_zoom_controls.button_minus.addEventListener(MouseEvent.CLICK, zoomOutFunction);
new_zoom_controls.button_plus.addEventListener(MouseEvent.CLICK, zoomInFunction);
new_zoom_controls.button_left.addEventListener(MouseEvent.CLICK, rotateLeftFunction);
new_zoom_controls.button_right.addEventListener(MouseEvent.CLICK, rotateRightFunction);
new_zoom_controls.button_rotate.addEventListener(MouseEvent.CLICK, toggleRotateFunction);
function rotateRightFunction(e:MouseEvent){
6. //loaded_swf.rotateRight();
}
function rotateLeftFunction(e:MouseEvent){
//loaded_swf.rotateLeft();
}
function zoomInFunction(e:MouseEvent){
//loaded_swf.zoomIn();
}
function zoomOutFunction(e:MouseEvent){
//loaded_swf.zoomOut();
}
function toggleRotateFunction(e:MouseEvent){
//loaded_swf.toggleAutoRotate();
if(new_zoom_controls.button_rotate.currentFrame == 1){
new_zoom_controls.button_rotate.gotoAndStop(2);
}
else new_zoom_controls.button_rotate.gotoAndStop(1);
}
new_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, gotSwf);
}
If you follow steps 1-6 you see my steps of loading the .swf, mouse event listeners and click handlers, then the object call of the var loaded_swf:Object;
public static function rotateLeft():void
{
object.yaw(animation_turning_speed);
}
public static function rotateRight():void
{
object.yaw(-animation_turning_speed);
}
if I run the main.fla and try to click the buttons. This happens.
ReferenceError: Error #1069: Property rotateRight not found on
ThreedsKU39web and there is no default value. at MethodInfo-82()
ReferenceError: Error #1069: Property rotateLeft not found on
ThreedsKU39web and there is no default value. at MethodInfo-83()
I actually stumbled upon the answer before I finished submitting this as I went through the code to copy it. But after spending a few hours of frustrating moments on this last night, I will post it to ensure the next guy doesn't meet the same demise.
The answer was in the function of the runtime-loaded swf class.
public static function rotateRight():void
{
object.yaw(-animation_turning_speed);
}
It turns out it only needs to be public function instead of public static.
Mainly human error as after the file was working, I attempted to copy the code over to all my other object files, and somehow static got back in there and messed it up. So for future reference when loading in the external swf, public function should do the trick. *Note that many of my variables were returning errors until being declared as public static though.