Can I put two or more actionscript classes in one .as file like this:
//A.as
package classes {
public class A {
public function A() {
var b:B = new B();
}
}
internal class B {
public function B() {
trace("Hello");
}
}
}
It doesn't work in Flash Builder:
A file found in a source-path can not have more than one externally
visible definition. classes:A; classes:B
If it possible, I'm going to ask next question.
Can I place two or more packages with multiple classes in one .as file?
No and no. The following works:
//A.as
package classes {
public class A {
public function A() {
var b:B = new B();
}
}
}
class B { // <--- Note the class is outside of the package definition.
public function B() {
trace("Hello");
}
}
The class B is only visible to the class A - you cannot have more than one visible class in one file (exactly what the error message states). And you cannot have more than one package in a file.
Related
As the question states, I want to know how I can make a function in a class that other classes can access, but subclasses cannot. I have a class that has some public getters and setters that I want my document class to have access to call, but I don't want the subclass to have these functions because they'd be useless on the subclass.
For example
public class SomeClass
{
public function SomeClass() {}
public function notInherited():void { trace("Not inherited"; }
}
public class OtherClass extends SomeClass
{
public function OtherClass()
{
notInherited(); //Want this to return an error
}
}
public class HasAccess
{
public function HasAccess()
{
notInherited(); //Not inherited
}
}
I know this probably has something to do with custom namespaces, but after searching up about them I still don't really have much understanding of how they work. That's about it; thanks for reading.
You can't do this quite in the general terms you've asked, but you can do this if you put your document class and your other class in the same package and use internal instead of public, and you put your sub-class in a different package. The internal keyword limits access to classes in the same package.
Example (notice the package statements):
package main {
public class Main extends MovieClip {
public function Main() {
var stuff:Stuff = new Stuff();
stuff.doStuff();
}
}
}
package main {
public class Stuff {
internal function doStuff():void { }
}
}
package other {
public class OtherStuff extends Stuff {
public function OtherStuff() {
// no access to this.doStuff()
}
}
}
As for using a namespace, this can be a good option to make the intent of your code more clear, but it doesn't actually limit access in any new way, it just requires access to be more deliberate: while the namespace does hide visibility of the API to anyone who doesn't use the namespace, anyone can use the namespace and have access to the API without any additional limits (ie public, internal and protected).
Still, this may be all you are after. Here's an example which uses a public namespace and no packages:
// my_stuff.as
package {
public namespace my_stuff;
}
// Stuff.as
package {
public class Stuff {
my_stuff function doStuff():void { }
}
}
// Main.as
package {
import flash.display.MovieClip;
public class Main extends MovieClip {
public function Main() {
use namespace my_stuff; // you can put this above the class to give the entire class access to the namespace
var stuff:Stuff = new Stuff();
stuff.doStuff();
}
}
}
// OtherStuff.as
package {
public class OtherStuff extends Stuff {
public function OtherStuff() {
this.doStuff(); // not allowed
this.my_stuff::doStuff(); // allowed
// also allowed
use namespace my_stuff;
this.doStuff();
}
}
}
(Note that if your namespace is in a package, ex package stuff { public namespace my_stuff }, you must import the namespace just like a class, for example: import stuff.my_stuff)
I have a parent class called 'main.as'. I am trying to get the child class to call main's function. They both reside in the same folder.
// main.as //
package {
public class main extends MovieClip {
public function main() {
var child:child_mc = new child_mc(this);
}
public function callFunction():void {
trace("Done it");
}
}
}
.
// child.as //
package {
import main;
public class child extends MovieClip {
private var main:MovieClip = new MovieClip();
public function child(main:MovieClip):void {
this.main = main;
main.callFunction();
}
}
}
This is the error I've been getting:
TypeError: Error #1006: callFunction is not a function.
so I tried doing a trace like this
trace(main.callFunction);
and it says undefined. Can someone tell me what I am missing. I get this feeling its a very basic thing that I have overlooked!
Your "child" package is defined as "main". I'm not even sure how it complied, let alone run to the point of showing the error message you got.
I believe the code below should do what you expected.
(I also took the liberty to rename the classes to use CamelCase (with initial caps) to adhere to best practices and to be easier to distinguish from variable names.)
Main.as
package {
public class Main extends MovieClip {
public function Main() {
var child:ChildMC = new ChildMC();
child.main = this;
}
public function callFunction():void {
trace("Done it");
}
}
}
EDIT: I just saw your comment that points out that child_mc is a MovieClip in the Library. I guess then that the child class is set as the Base Class of the child_mc?
If so, you cannot pass properties through the instantiator, you need to find another way to pass along the instance of the Main class to the Child class.
One way would be to add a setter, like the following:
Child.as (Base Class for ChildMC)
package {
public class Child extends MovieClip {
private var _main:Main;
public function Child() {
}
public function set main(main:Main):void {
this._main = main;
this._main.callFunction();
}
}
}
Does this work well as a Singleton in actionscript? i.e. are there any gotchas I should be aware of, and is it true that only one instance of AVManager would be created in this case:
Note that I do get the expected output (only one time of "instantiated first time" and numbers follow sequence):
instantiated first time! 1
FILE 1: 2
FILE 2: 3
and finally 4
Here are the files....
AV_CONFIG.as:
package {
public class AV_CONFIG {
public static var AVM:AVManager = new AVManager();
}
}
AVManager.as:
package {
import flash.events.EventDispatcher;
public class AVManager extends EventDispatcher {
public var someConstantData:uint = 1;
public function AVManager() {
trace('instantiated first time!', someConstantData);
}
}
}
Then:
File1.as:
package {
import AV_CONFIG;
import flash.display.Sprite;
public class File1 extends Sprite {
public function File1() {
AV_CONFIG.AVM.someConstantData++
trace('FILE 1:', AV_CONFIG.AVM.someConstantData);
}
}
}
File2.as:
package {
import AV_CONFIG;
import flash.display.Sprite;
public class File2 extends Sprite {
public function File2() {
AV_CONFIG.AVM.someConstantData++
trace('FILE 2:', AV_CONFIG.AVM.someConstantData);
}
}
}
Main.as (the DocumentClass):
package {
import AV_CONFIG;
import flash.display.Sprite;
public class Main extends Sprite {
public function Main() {
var f1:File1 = new File1();
var f2:File2 = new File2();
AV_CONFIG.AVM.someConstantData++
trace('and finally', AV_CONFIG.AVM.someConstantData);
}
}
}
Generally with singletons you want to:
Limit or dissolve the ability to create instances of that class.
Create a means of getting an instance of that class statically.
Example:
public class AvManager
{
private static var _instance:AvManager;
internal static var created:Boolean = false;
public function AvManager()
{
if(AvManager.created)
{
throw new Error("Cannot created instances of AvManager, use AvManager.instance.");
}
AvManager.created = true;
}
public static function get instance():AvManager
{
if(_instance == null)
{
_instance = new AvManager();
}
return _instance;
}
public function test():void
{
trace("Working.");
}
}
Where you could now use:
AvManager.instance.test(); // Working.
The biggest gotcha is allowing global access to something if its state can be changed. If this is a project where you expect the codebase to be maintained for longer than a week or so and you think it's likely to have more than 500 lines of code, I'd strongly suggest avoiding doing this--I can tell you from experience that in a large project it can be difficult to impossible to figure out which of the hundreds of Classes that have access to your Singleton made the change to its state that is causing a given bug.
Next, requirements have a way of changing. What if you suddenly need 2 AVManagers? You'll find that you've created so many baked-in references to your static that changing it will blow the entire project to heck. Again, I speak from experience here. If you use dependency injection (which is just a scary way of saying that Classes that need an AVManager have a property that is populated from the outside), then these types of changes become easy...just give them a different AVManager, done.
Finally, if you have any pretensions of wanting to do Test Driven Development, using globals/statics in this way will essentially make all that code untestable. You can't provide an alternate AVManager for testing, since all the Classes with a dependency on it are hard-wired to go get that specific one.
Good luck!
Yeah this works fine, a different method is to put an AVManager right in its own class file at the top:
private static var AVM:AVManager = new AVManager();
and get it when required with a function in the AVManager class like this:
public static function GetInstance():AVManager {
return AVM;
}
This setup isn't necessary but provides some nice little protection by disallowing direct access.
Good luck with your project.
See this code as an attempt for creating something different.
An other Singleton in AS3 :
First an Interface :
package test {
public interface Foo {
function func0():void;
function func1(arg:String):String;
}
}
And then a Singleton :
package test {
public class BASIC_FOO {
public static const BASIC_FOO:Foo = new BasicFoo();
}
}
import test.Foo;
class BasicFoo implements Foo {
public function func0():void {
}
public function func1(arg:String):String {
return arg;
}
}
I would like to read the source of the flash.net.FileReference class. Is this possible? Where can I find the source files, do they come with the Adobe Flash or Flash Builder?
To read the flash package files, you can find the playerglobal.swc - change the name to playerglobal.zip and unzip the package. Then, decompile the library.swf file and get the script files. Here's what I found for FileReference:
//FileReference
package flash.net
{
import flash.events.*;
import flash.utils.*;
public class FileReference extends flash.events.EventDispatcher
{
public function FileReference()
{
super();
return;
}
public function upload(arg1:flash.net.URLRequest, arg2:String="Filedata", arg3:Boolean=false):void
{
}
private function _load(arg1:flash.utils.ByteArray):void
{
}
public function load():void
{
this._load(new ByteArray());
return;
}
public function get size():uint
{
}
public function get type():String
{
}
public function browse(arg1:Array=null):Boolean
{
}
public function get name():String
{
}
public function get creator():String
{
}
public function get creationDate():Date
{
}
public function download(arg1:flash.net.URLRequest, arg2:String=null):void
{
}
public function get modificationDate():Date
{
}
public function get data():flash.utils.ByteArray
{
}
public function cancel():void
{
}
private function _save(arg1:flash.utils.ByteArray, arg2:String):void
{
}
public function save(arg1:*, arg2:String=null):void
{
var defaultFileName:String=null;
var data:*;
var d:flash.utils.ByteArray;
var loc1:*;
data = arg1;
defaultFileName = arg2;
d = new ByteArray();
if (data == null)
{
throw new ArgumentError("data");
}
if (data is String)
{
d.writeUTFBytes(data as String);
}
else if (data is XML)
{
d.writeUTFBytes((data as XML).toXMLString());
}
else if (data is ByteArray)
{
d.writeBytes(data as ByteArray);
}
else
{
try
{
d.writeUTFBytes(data);
}
catch (e:Error)
{
throw new ArgumentError("data");
}
}
d.position = 0;
if (defaultFileName == null)
{
defaultFileName = "";
}
this._save(d, defaultFileName);
return;
}
}
}
I highly recommend not changing this file and rather extend it and override the functions you need to modify. Otherwise, you'll need to recompile the library.swf and create a custom playerglobal.swc.
As others mentioned you can see the sources for the Flash and Flex framework classes. The exact location will vary.
For Flash CS4 on Windows 7:
C:\Users\<your_user>\AppData\Local\Adobe\Flash CS4\en\Configuration
For Flex:
...\flex_sdk\frameworks\projects\framework\src
You CAN change any framework class you want as long as you're careful. In Flash nomenclature this is referred to as Monkey Patching. Create a class in your project with the same full package structure and class name as the framework class and the compiler will find and use your custom class instead of the framework class.
There are some complications in doing this with framework RSL's. For that see here:
How to Monkey Patch when using Flex RSLs
http://blogs.adobe.com/dloverin/2010/01/how_to_monkey_patch_when_using_flex_rsls.html
This does not apply to built-in or "intrinsic" classes. Those are built-into the player and wills till have stub code in the above source locations. You can't actually change intrinsic classes.
Any of the "stuff" that is available for you to view are located (for Win7 anyway) in C:\Users\<your_user>\AppData\Local\Adobe\Flash CS4\en\Configuration
The Flash CS4 portion might change depending on the version you have. Classes are in the Classes folder inside configuration.
So, how do we write a class over several files in action script 3?
In C# there's the "partial" keyword.
In C++ it's natural (you just "#include ..." all files).
In Flex 3, in a component, you add this tag: <mx:Script source="myfile.as"/>.
How do I split the following class into several files;
package package_path
{
public class cSplitMeClass
{
public function cSplitMeClass()
{
}
public function doX():void
{
// ....
}
public function doY():void
{
// ....
}
}
}
For example I want to have the doX() and doY() functions implemented in another ".as" file.
Can I do this?
And please, don't tell me something like "a good practice is to have them in one file" :)
As per your request, I'm sparing you the "best practices lecture". So, I'll just say there's an include directive in AS 3.0, which could help you out here.
Basically, you can do:
package package_path
{
public class cSplitMeClass
{
public function cSplitMeClass()
{
}
include "the_file_where_doX_and_doY_live.as"
}
}
And then in "the_file_where_doX_and_doY_live.as"
public function doX():void
{
// ....
}
public function doY():void
{
// ....
}
You could do it with inheritance:
// file: cSplitMe1.as
class cSplitMe1 {
function doX() {
// ...
}
// file: cSplitMe2.as
class cSplitMe2 extends cSplitMe1 {
function doY() {
// ...
}
// file: cSplitMe.as
class cSplitMe extends cSplitMe2 {
function cSplitMe() {
doX();
doY();
}
}
It's good practice, nothing wrong with that.
There's the import keyword. Example:
import Class_A.as;
import Class_B.as;
Now of course in order to use them, you need to declare them, preferably in your constructor.
public function Class_C()
{
//Create a new instance of Class_A
var objA:Object = new Class_A("parameter one", "parameter two");
//Create a new instance of Class_B
var objA:Object = new Class_B("parameter one", "parameter two");
}
Of course it all depends on how you're going to make this work. I would also suggest you use a Main class from where you could run your code. I guess you already knew that though.
Good luck.