In AS3, why do we put our import statements in the package statement, and not inside the Class declaration?
This is a typical (but rather pointless) AS3 class:
package my.foo.package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class FooClass extends MovieClip
{
public static const EVENT_TIME_UP:String = 'timeUpEvent';
public function FooClass()
{
var timer:Timer = new Timer(2000, 1);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.start();
}
private function timerHandler(e:TimerEvent):void
{
dispatchEvent(new Event(FooClass.EVENT_TIME_UP));
}
}
}
But why are all the import statements meant to go all the way up there, outside on the Class? The class works perfectly fine when I move the imports to inside the class declaration like below.
package my.foo.package
{
import flash.display.MovieClip;
public class FooClass extends MovieClip
{
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
public static const EVENT_TIME_UP:String = 'timeUpEvent';
public function FooClass()
{
var timer:Timer = new Timer(2000, 1);
timer.addEventListener(TimerEvent.TIMER, timerHandler);
timer.start();
}
private function timerHandler(e:TimerEvent):void
{
dispatchEvent(new Event(FooClass.EVENT_TIME_UP));
}
}
}
It's only the MovieClip import that needs to be in package, because my class is extending it.
There is nothing helpful about this in the Adobe AS3 coding conventions.
So why do we put the imports in the package and not the class that's actually using them. The package is not using the imported classes is it? And why does it still work if I move the imports into the Class?
This is simply a convention that's in use so there is one central place to view all of the imports. Let's say we take your logic to the next extreme and place an import statement on the line just before every variable we declare (which compiles just fine by the way). We'd wind up needlessly duplicating import statements whether on purpose or by accident. Also, someone wanting to see what dependencies a given file has would have to scan the whole file rather than looking at just the top of the file. Your point of putting the imports within the class declaration isn't as crazy, but you'd still wind up with the problem of imports scattered throughout a file if your file declares more than one class (as in the case of internally used classes, for example).
Related
trying to make a time delay before redirection to a specific web page , I got many errors during the compiling process , sorry new to actionscript :
package
{
import flash.display.*;
import flash.net.*;
import flash.system.*;
import flash.utils.*;
import flash.events.*;
public class test extends flash.display.Sprite
{
public function test()
{
super();
flash.net.navigateToURL(new flash.net.URLRequest("http://youpassed-theexam.com/congrats"), "_self");
return;
}
}
setInterval(test,5000);
}
A couple of issues with your code:
Constructors of classes are immediately called once the class is
instantiated. You should create a separate method and call that with
a delay from within your constructor.
setInterval would fire repeatedly after every set interval. You
should rather use setTimeout.
Classes should have a Sentence caps naming convention, so Test and not test. Just a best practice. Nothing wrong syntactically.
Constructors do not return anything so we do not need the return statement.
Once you have imported a class, you do not need to write the full name of the class to access it's methods.
Try to avoid * based import statements. It does tend to import a lot more classes than just the required class. Again, just a best practice.
So your code should look something like this below:
package
{
import flash.display.Sprite;
import flash.net.URLRequest;
import flash.net.navigateToURL;
import flash.utils.setInterval;
import flash.utils.setTimeout;
public class Test extends flash.display.Sprite
{
public function Test()
{
super();
setTimeout(gotoURL, 5000);
}
protected function gotoURL():void
{
navigateToURL(new URLRequest("http://youpassed-theexam.com/congrats"), "_self");
}
}
}
Hope this helps. Cheers.
I am using Flash Builder 4.7 and have created a Worker Class. Below is the code:
package co.fuix.mobile.system.model
{
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.events.Event;
import flash.system.MessageChannel;
import flash.system.Worker;
import flash.utils.getDefinitionByName;
import mx.managers.SystemManager;
public class InstantMessengerWorker extends Sprite
{
private var bm:MessageChannel;
private var mb:MessageChannel;
public function InstantMessengerWorker()
{
super();
bm = Worker.current.getSharedProperty("BACK_TO_MAIN_CHANNEL");
mb = Worker.current.getSharedProperty("MAIN_TO_BACK_CHANNEL");
mb.addEventListener(Event.CHANNEL_MESSAGE, onMainToBack);
}
protected function onMainToBack(event:Event):void
{
if(mb.messageAvailable){
var s:SystemManager;
trace('*'+mb.receive());
trace('**'+mb.receive());
trace('***'+mb.receive());
trace(mx.core.FlexGlobals.topLevelApplication.myVariable);
}
}
}
}
How do I reference a variable in the main mxml file. I know how to use message channels but I want to get that variable straight.
When I run the above code, this part
trace(mx.core.FlexGlobals.topLevelApplication.myVariable);
is giving me an error.
Any help will be regreatly appreciated
You can't access a variable from the main app like that. They are running separately. What you need to do is:
Link to Adobe docs
Trying to addChild() inside a movie clip in the stage from one of my classes. The code looks like this
package {
import flash.display.SimpleButton;
import flash.events.MouseEvent;
import flash.display.MovieClip;
public class createFlask extends SimpleButton {
public function createFlask() {
addEventListener(MouseEvent.CLICK, createAFlask);
}
private function createAFlask(e:MouseEvent):void
{
var Flask = new flask ;
Flask.x = stage.width/2;
Flask.y = stage.height/2;
stage.experiment.addChild(Flask);
}
}
This gives an error as
Access of possibly undefined property experiment through a reference
with static type flash.display:Stage.
Any solutions?
Just omit "stage".
Instead use
experiment.addChild(Flask);
That will work.
I'm trying to load in a remote SWF and access it's methods and properties, using an interface. (There's a similar question here that got as far as "that's weird!" but didn't resolve it: Loading swf and using it through interface)
My remote SWF looks like this:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.system.Security;
import IMultiplayer;
[SWF(width="238", height="60", frameRate="60", backgroundColor="#FFFFFF")]
public class Main extends Sprite implements IMultiplayer
{
public function init(e:Event):void
{
}
public function TEST():void
{
trace("TEST()");
}
}
}
I then have an interface that looks like this:
package
{
import flash.events.*;
import flash.display.*;
public interface IMultiplayer
{
function init(e:Event):void;
function TEST():void;
}
}
And finally, I've got a loader class that pulls down the SWF and tries to cast it as the same interface that the remote SWF implements. EDIT - apologies for length, was asked to post the full source:
package uk.co.MyDomain
{
import flash.display.DisplayObject;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.ErrorEvent;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.TimerEvent;
import flash.net.URLRequest;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.system.Security;
import flash.system.SecurityDomain;
import flash.utils.Timer;
import uk.co.MyDomain.*;
import utils.Console;
public class MultiplayerLoader extends Sprite
{
private var ld:Loader;
private var _environment:String;
public var _mpInstance:IMultiplayer;
private const SANDBOX_SWF:String = "http://static.sandbox.dev.MyDomain.co.uk/smartfoxtest/dev/swf/MP.swf";
public function MultiplayerLoader(environment:String)
{
_environment = environment;
}
public function loadMultiplayer():void
{
ld = new Loader();
var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
ld.contentLoaderInfo.addEventListener(Event.COMPLETE, multiplayerLoaded);
ld.contentLoaderInfo.addEventListener(ErrorEvent.ERROR, onLoadError);
ld.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIOLoadError);
ld.contentLoaderInfo.addEventListener(IOErrorEvent.DISK_ERROR, onDiskError);
ld.contentLoaderInfo.addEventListener(IOErrorEvent.NETWORK_ERROR, onNetworkError);
ld.contentLoaderInfo.addEventListener(IOErrorEvent.VERIFY_ERROR, onVerifyError);
if(Security.sandboxType == Security.REMOTE)
{
trace('[MP Loader] Loading with context');
ld.load(new URLRequest(SANDBOX_SWF), context);
}
else
{
trace('[MP Loader] Loading with NO context');
ld.load(new URLRequest(SANDBOX_SWF));
}
}
private function onIOLoadError(e:IOErrorEvent):void
{
notifyFailure('IOLoadError');
}
private function onDiskError(e:IOErrorEvent):void
{
notifyFailure('IOLoadError');
}
private function onNetworkError(e:IOErrorEvent):void
{
notifyFailure('IOLoadError');
}
private function onVerifyError(e:IOErrorEvent):void
{
notifyFailure('IOLoadError');
}
private function onLoadError(e:ErrorEvent):void
{
notifyFailure('IOLoadError');
}
private function multiplayerLoaded(e:Event):void
{
var tester:IMultiplayer = e.currentTarget.content as IMultiplayer;
Console.log('Loaded: ' + tester);
dispatchEvent(new MultiplayerEvent(MultiplayerEvent.SWF_LOAD_SUCCESS));
}
private function notifyFailure(reason:String):void
{
var failEvent:MultiplayerEvent = new MultiplayerEvent(MultiplayerEvent.SWF_LOAD_FAILURE);
failEvent.params = {'reason':reason}
dispatchEvent(failEvent);
}
}
}
Now, if I DON'T cast it to use the interface, I can trace it out successfully and call functions (so e.target.content.TEST() will fire). However, as soon as I cast it to the interface, it fails.
Any ideas?
EDIT
OK, I'm getting the same issue with a custom event class that's shared between both applications. Flash errors, saying it cannot convert from one class to the other - even though they're identical they're in different projects, and so I imagine different namespaces. I assumed that loading into the same applicationDomain would fix this, but it hasn't. Is there any other way I can get around this without resorting to a common library/SWC or similar?
I think this might be an issue of the application domain. The loaded SWF resides in its own application domain so it does not share the exact same interface. Try to load the swf into the »current application domain«, using the applicationDomainproperty of the Loader's LoaderInfo Object.
look here
good luck…
EDIT::
it has to be done in the loaders load method
var context:LoaderContext = new LoaderContext(false, ApplicationDomain.currentDomain);
var loader:Loader = new Loader();
loader.load(new URLRequest("myButtons.swf"), context);
from here
EDIT 2::
Once I ran into an even more strange error, it was caused by the fact that i created an interface, compiled the »to load files« and »file that loaded«, changed the interface through adding a method and forgot to compile the »to load files« (there were a lot). Perhaps happened something like this…
EDIT 3::
If I remember right than one has to wait for the Event.INIT event of loaded swf's, first after this event the constructor of the loaded swf ran.
EDIT 4::
found this, perhaps you need to do:
var YourInterfaceClass:Class = ApplicationDomain.currentDomain.getDefinition( "YourInterface" ) as Class;
var myInstance:YourINterface = event.target.content as YourInterface;
I have this code:
package graphics {
import flash.display.Sprite;
import flash.events.*;
public class Ball extends Sprite {
public function Ball(_stage){
_stage.addChild(this);
drawBall();
}
private function drawBall(){
graphics.beginFill(0x0000CC);
graphics.lineStyle(2,0x000000,1);
graphics.drawCircle(0,0,10);
graphics.endFill();
}
}
}
ADDED:
and the class that I pass to mxmlc:
package {
import flash.display.Sprite;
import graphics.*;
[SWF(width='1024', height='768', backgroundColor='#FFFFFF', frameRate='30')]
public class Application extends Sprite {
public function Application(){
var ball:Ball = new Ball(this);
}
}
}
Except that when I compile, I get the following error:
ball.as(11): col: 14 Error: Call to a possibly undefined method beginFill.
graphics.beginFill(0x0000CC);
^
Along with the other three graphics.x() calls.
I am probably doing something wrong here, but I do not know what. Do you?
Just use this.graphics.method to avoid confusions created by your package name.
Edit - after comment.
After some messing around, it seems that though this.graphics traces as a correct Graphics object as expected, the this.graphics.method is looked in the Ball class. Don't know what messes this up like this, but it can be solved with a simple casting.
package graphics {
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.*;
public class Ball extends Sprite {
public function Ball(_stage) {
_stage.addChild(this);
drawBall();
}
private function drawBall() {
var g:Graphics = this.graphics as Graphics;
g.beginFill(0x0000CC);
g.lineStyle(2,0x000000,1);
g.drawCircle(0,0,10);
g.endFill();
}
}
}
Good luck
I am afraid the problem must be elsewhere in your code. If I take your class and clean it up so it compiles like so:
package
{
import flash.display.Sprite;
public class Ball extends Sprite
{
public function Ball()
{
drawBall();
}
private function drawBall():void
{
graphics.beginFill(0x0000CC);
graphics.lineStyle(2,0x000000,1);
graphics.drawCircle(0,0,10);
graphics.endFill();
}
}
}
$ mxmlc Ball.as
Loading configuration file [...]/flex-config.xml
/private/tmp/actionscript/Ball.swf (666 bytes)
It draws a blue ball in the top left corner of the screen. So your problem with graphics must be related to code which you have not shown here.
Edit: Based on the new information:
Your namespace graphics for the class Ball conflicts with the property name graphics. You need to rename the package and the directory it lives in.
Your class can not add itself to the stage. It has no reference to the stage until it has been added to the display list. Your application class needs to both create the ball and add it to the stage.
Also, it's just stage, not _stage.