i've used a Loader and URLRequest to download a .png from the internet and add it to my display list. since it's already a bitmap, does it have built in bitmap data already? or do i have to create the bitmap data myself?
also, why does the same trace statement return false in the mouseMoveHandler when it outputs true in the displayImage function?
var imageLoader:Loader = new Loader();
imageLoader.load(new URLRequest("http://somewebsite.com/image.png"));
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, displayImage);
function displayImage(evt:Event):void
{
addChild(evt.target.content);
addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
trace(evt.target.content is Bitmap); //outputs 'true'
}
function mouseMoveHandler(evt:MouseEvent):void
{
trace(evt.target.content is Bitmap); //outputs 'false'
}
A quick search of the AS3 docs tells me that Bitmap has a bitmapData property.
You are getting different rusults in each trace because you are tracing different things. try just tracing the property rather that "is Bitmap", to see what is actually stored there.
Your first trace you are tracing an Event, your second a MouseEvent. Your displayImage function is a "Loader Complete handler", so target will be a LoaderInfo object. In a LoaderInfo object, target refers to "The loaded DisplayObject associated with this LoaderInfo object". But in a MouseEvent the target will be different. You will need to refer to the docs for each event to find out what the target will be.
Also, I think you will need to add the mouse move event listener to the stage, or it wont work e.g.
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
Related
I started using as3 a while ago, and mostly used starling instead of native flash objects. Today I decided to give a try to raw flash, and created a simple button:
private var _button: SimpleButton;
public function Main()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
_button = new SimpleButton(new BUTTON); //BUTTON is an embedded bitmap
addChild(_button);
_button.useHandCursor = true;
_button.addEventListener(MouseEvent.CLICK, OnClick);
}
private function OnClick(e:MouseEvent):void
{
trace("clicked");
}
This would definely work in starling, but I found that the click event won't dispatch to the button for some reason. Neither is hand cursor shown on mouse over. I tried mouse over, mouse up and other mouse events, but none of them work. I checked that the button is correctly added to stage. Also, when I add a mouse click event listener to the stage itself, clicks register normally. When I add a listener to Main, no events are registered again.
I'm probably misunderstanding something obvious. Maybe I need to dispatch events manually down to the children? But that would be strage, though. Or can it be a bug in FlashDevelop? Please, help.
The constructor of SimpleButton takes 4 optional parameters:
public function SimpleButton(upState:DisplayObject = null,
overState:DisplayObject = null,
downState:DisplayObject = null,
hitTestState:DisplayObject = null)`
of which you supply the first one (upState):
_button = new SimpleButton(new BUTTON); //BUTTON is an embedded bitmap
The others default to null. That includes hitTestState which is the same as property of the class hitTestState:
Specifies a display object that is used as the hit testing object for the button. [...] If you do not set the hitTestState property, the SimpleButton is inactive — it does not respond to user input events.
It also includes a solution to your problem:
For a basic button, set the hitTestState property to the same display object as the overState property.
However, if all you want is to add click functionality to that Bitmap, which it doesn't have on its own, because it's not an InteractiveObject, simply use a Sprite:
// entry point
_button = new Sprite();
_button.addChild(new BUTTON); //BUTTON is an embedded bitmap
addChild(_button);
_button.useHandCursor = true;
_button.addEventListener(MouseEvent.CLICK, OnClick);
Use SimpleButton only if you want the functionality of its 4 states.
Please be careful with the overloaded term "stage":
I checked that the button is correctly added to stage.
If you mean the "drawing area" that you can see in the Adobe Flash IDE or the main time line with "stage", then yes, you'd be correct that your button is added to that.
The stage property of DisplayObject however is something different. It's the top most element of the display list and the container that the instance of your Main class is added to, which happens at the start of the execution of your .swf in the FlashPlayer.
As your Main class adds the _button to itself by calling its ownaddChild(), the button is added to the instance of Main and not stage, which are two different objects.
Ok, here's a weird thing:
I have a class, which is a MovieClip that has 2 children, MovieClips also.
I add the children to him and base MovieClip to stage.One of the children is animated.
All is perfect.
Now when I add MouseEvent.MOUSE_UP on the children, all works fine.
Yet if I set useWeakReference to true (the 5th parameter) mouse event does not fire anymore,but the items are on stage. Basically, somehow, they are not in the memory.
Of course if I add a simple onEnterFrame that does nothing to base MovieClip, it traces the MovieClip, yet the MouseEvents does not trigger. That means the object is still there, but somehow for flash is not
Now, this is a simplified concept, that is easy to clean, but my code is very big and a simple removeEventListener is not a solution. At least not a simple one.
What are your suggestions to work around this?
I'm not sure how complex your code is, but if each movieclip has MOUSE_UP event handler - some function, you could indeed use removeEventListener MOUSE_UP function. For instance:
var mc:MovieClip = new MovieClip();
mc.addEventListener( MouseEvent.MOUSE_UP, onMU );
function onMU(e:MouseEvent){
var target = MovieClip(e.currentTarget);
target.removeEventListener( MouseEvent.MOUSE_UP, onMU );
}
This way you can have multiple movieclips and remove listeners without knowing object name.
Alternatively you could modify your code to add aray of all added events and then listen to REMOVE_FROM_STAGE event. Something like this:
var mc:MovieClip = new MovieClip();
mc.events = [];
mc.events.push( { evt: MouseEvent.MOUSE_UP, fn: onMU } );
mc.addEventListener( MouseEvent.MOUSE_UP, onMU } )
//or use events array reference to keep events and functions in one place.
//when object is removed you can iterate through events array and automatically remove
//all listeners
Another alternative would be to create Class that extends MovieClip - but since your code is huge you probably don't want to do that.
You can also look on Robert Penner's Signals library, which is interesting alternative to AS3 events. (https://github.com/robertpenner/as3-signals)
I am trying to add a child instance of an object to the stage, then allow the user to drag and drop this object (in this case, a movie clip) on the stage. However, I am getting the following error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at working_copy_fla::MainTimeline/dragObject()
So, that is my first problem. Then second problem, is I have not found an answer as to how to make a child object (specifically, a movie clip) able to properly be dragged and dropped on the stage.
Here is my code:
// Allow buttons to bring objects to the stage
myButton.addEventListener(MouseEvent.CLICK, addImage);
function addImage(event:MouseEvent):void
{
var myImage:Image_mc = new Image_mc();
stage.addChild(myImage);
// Center the object
myImage.x = 300;
myImage.y = 300;
// Allow the object to be drag and dropped
myImage.addEventListener(MouseEvent.MOUSE_DOWN, startDragging);
myImage.addEventListener(MouseEvent.MOUSE_UP, stopDragging);
}
function startDragging(event:MouseEvent):void
{
event.target.x = event.target.parent.mouseX - event.target.mouseX
event.target.y = event.target.parent.mouseY - event.target.mouseY
stage.addEventListener(MouseEvent.MOUSE_MOVE, dragObject);
}
function dragObject(event:MouseEvent):void
{
event.target.x = event.target.parent.mouseX - event.target.mouseX
event.target.y = event.target.parent.mouseY - event.target.mouseY
}
function stopDragging(event:MouseEvent):void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, dragObject);
}
EDIT
I figured it out, and the solution was as simple as looking to the sample code in Adobe Flash (using CS6). Here is my code now:
// Allow buttons to bring objects to the stage
myButton.addEventListener(MouseEvent.CLICK, addImage);
function addImage(event:MouseEvent):void
{
var myImage:Image_mc = new Image_mc();
stage.addChild(myImage);
// Center the object
myImage.x = 300;
myImage.y = 300;
// Allow the object to be dragged
myImage.addEventListener(MouseEvent.MOUSE_DOWN, clickToDrag);
}
function clickToDrag(event:MouseEvent):void
{
event.target.startDrag();
}
stage.addEventListener(MouseEvent.MOUSE_UP, releaseToDrop);
function releaseToDrop(event:MouseEvent):void
{
event.target.stopDrag();
}
The key here was that I have created universal functions (clickToDrag and releaseToDrop) that will accept input from any object (so I can re-use these functions with other images that I add to the stage). This code works with multiple children on the stage (all can be drag and dropped at any time).
The only problem I am having with it now is that I am getting this error whenever I spawn a child element (by clicking on the myButton button instance):
ReferenceError: Error #1069: Property stopDrag not found on flash.display.SimpleButton and there is no default value.
at working_copy_fla::MainTimeline/releaseToDrop()
This error is not stopping the application from working; everything still runs fine. But I would still like to figure out why this error is occuring. My guess is that whatever is using "stopDrag" (should just be a movie clip) is not capable of that method.
event.target.x = event.target.parent.mouseX - event.target.mouseX
The above code assumes that 'event.target' is the stage, right (because you added the listener to the stage)? So you're trying to change the x/y of the stage? No. The start/stopDragging should make a reference to the object being dragged, available as a private class variable, which is visible to the dragObject method. Also, what is the stage's parent ('event.target.parent.mouseX')? There is no parent to the stage. This is probably what the "null object reference" is refering to.
EDIT
I'm used to Object-Oriented AS3 (highly recommended), but I'm guessing that programming on the 'timeline' the following should work. Declare a variable outside of your functions, something like:
var objectCurrentDragging:DisplayObjectContainer;
Then in your 'addImage' function, use the following code to make objectCurrentDragging reference the object which you want to drag:
objectCurrentDragging = myImage;
Then in the dragObject function, simply reference objectCurrentDragging:
objectCurrentDragging.x = ...
Hope that works out for you.
So I have finally figured it out. The key was not to add an event to the stage, but rather, to add the "releaseToDrop" function to the *MouseEvent.MOUSE_UP* event on the child element in the same function that adds it to the stage. Now I get no more errors, and it works with multiple instances of the child objects (movie clips) on the stage.
Here is the code that works:
// Allow buttons to bring objects to the stage
myButton.addEventListener(MouseEvent.CLICK, addImage);
function addImage(event:MouseEvent):void
{
var myImage:Image_mc = new Image_mc();
stage.addChild(myImage);
// Center the object
myImage.x = 300;
myImage.y = 300;
// Allow the object to be dragged
myImage.addEventListener(MouseEvent.MOUSE_DOWN, clickToDrag);
myImage.addEventListener(MouseEvent.MOUSE_UP, releaseToDrop);
}
function clickToDrag(event:MouseEvent):void
{
event.target.startDrag();
}
function releaseToDrop(event:MouseEvent):void
{
event.target.stopDrag();
}
I have loaded an external swf file which plays a flv file by default as swf is loaded. Now the problem is how do i remove the swf file from memory. my code :
var myLoader:Loader = new Loader();
var url:URLRequest = new URLRequest("ExternalSWF.swf");
myLoader.load(url);
detailMovieClip.movieHolder.addChild(myLoader);
I have tried many combinations of removeChild, unload and unloadAndStop but none works. I figure its all about not referencing correctly.
Update:
I went with the answer from Jegan, but it only work when i am testing in a dummy project which has only 1 numChildren, howver in real world code example numChildren reported 22 so i am not sure if that would be an issue. here is the real world code:
var myImageLoader:Loader;
var myImageRequest:URLRequest;
var theImagePath:String;
//part from xml processor function
theImagePath = "flash/"+myXML..item_video_link[n];
loadTheMovie(theImagePath);
function loadTheMovie(theImagePath):void{
myImageLoader = new Loader();
myImageRequest= new URLRequest(theImagePath);
myImageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE,showMeTheVideo);
myImageLoader.load(myImageRequest);
}
function showMeTheVideo(evt:Event):void{
detailsMovieClip_mc.details_video_holder.dynamicVideoHolder.addChild(myImageLoader);
}
stopVideo(sectionname):viod{
if(detailsMovieClip_mc.details_video_holder.dynamicVideoHolder.numChildren !=0){
trace("what is the number of children: "+numChildren);
myImageLoader.unloadAndStop();
detailsMovieClip_mc.details_video_holder.
dynamicVideoHolder.removeChild(myImageLoader);
}
}
stage.addEventListener(MouseEvent.CLICK, removeSWF);
function removeSWF (e:MouseEvent):void
{
if(detailMovieClip.movieHolder.numChildren !=0){
myLoader.unloadAndStop();
detailMovieClip.movieHolder.removeChild(myLoader);// empty the movieClip memory
}
}
OR
Name your Loader instance and then search by using getChildByName
myLoader.name = "myloader";
function removeSWF (e:MouseEvent):void
{
if(detailMovieClip.movieHolder.numChildren !=0){
Loader(detailMovieClip.movieHolder.getChildByName("myloader")).unloadAndStop();
detailMovieClip.movieHolder.removeChild(detailMovieClip.movieHolder.getChildByName("myloader"));// empty the movieClip memory
}
}
I guess this is because you are adding the loader to the scene itsef.
Either you want to keep this behavior, in this case there is a quick fix, remove the loader from the MovieClip by using removeChild(), then set the reference to null, or use the delete keyword.
Either you want to do it properly, in this case, listen for the LOADED event, adds the MovieClip contained by the loader.content to the target MovieClip. Then, when you want to unload it, remove the clip from the container using removeChild(), then loader.unload().
I have a 1.swf loads up a another 2.swf, while i doing things inside 2.swf like
1.swf is bigger
2.swf is smaller inside
stage.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
it keep refer to the parent's stage instead the 2.swf's stage.
Please help out. thanks
There is only one stage object, and it is always inherited from the root. Anytime you can access the property "stage" inside a DisplayObject (Sprite,MovieClip) it's actually just a reference to the root.stage that gets populated whenever that DisplayObject is added to the root stage, or a child of some object that eventually connects to the stage (the display list). The display list is just an object tree of various display objects that are connected to the root stage. Anyway so, about your question, if you just want to listen for events on your loaded swf do something like this:
var loader:Loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
loader.load(new URLRequest("swf2.swf"));
private function loadComplete(e:Event):void
{
var swf2Clip:MovieClip = loader.content as MovieClip;
swfClip.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
}
private function onMouseOut(e:MouseEvent):void
{
//Do something when swf2 is moused out.
}