views:

268

answers:

4

I figured out how to create a static method that is available everywhere, for example:

UtilLib.as:

package
{   
     public final class UtilLib
     {  
          public static function getTimeStamp():uint
          {
               var now:Date = new Date();
               return now.getTime();
          }
     }
}

I can access this everywhere by doing UtilLib.getTimeStamp() - Now, I want to create a new staic method called log(msg:String). This should log a message to a multi-line inputfield.

The problem however is that this inputfield must be created somewhere and must be accessible and visible all the time, and I don't want to pass it through the function parameters all the time as this would cause a lot of trouble (I'd have to pass it through objects aswell..).

So, how do I make a "public textfield" so my static log method can write to it?

UPDATE: I now tried the following class, with a static constructor (I think). However, the textfield object is not showing. When I do an addChild(debugField) after creating it, it gives me error 1180.

Logger.as

package
{
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.text.TextFieldType;

    public class Logger extends Sprite
    {
     public static var debugField:TextField;

     /* static block */
     {
      trace("Logger initializing.");
      debugField = new TextField();
      debugField.width = 500;
      debugField.height = 100;
      debugField.x = 100;
      debugField.y = 400;
      debugField.background = true;
      debugField.backgroundColor = 0xFFFFFF;
      debugField.defaultTextFormat = new CustomTextFormat();
      debugField.mouseWheelEnabled = true;
      debugField.multiline = true;
      debugField.type = TextFieldType.DYNAMIC;
     }

     public static function log(msg:String):void
     {
      if (debugField) debugField.appendText(msg);
     }

    }
}

I initialize it like this:

var test:Logger = new Logger();
addChild(test);

And I log a new message like this:

Logger.log("test");

Unfortunately, the textField is not showing.

A: 

Traditionally, the way you let static methods interact with private variables is to pass them in. Pass in a pointer to your textbox.

so instead of

public static function getTimeStamp():uint { ... }

you have

public static function writeTimeStamp(messageBox):uint { ... }

The syntax might be incorrect as I'm not an AS dev but, do you see what I mean? From there, that block of code can access messageBox as if it were a local variable. Well it is.

(I renamed the method name for clarity. You could even stop it returning a variable if it doesn't need to but you'll need to change the declaration further.)

Oli
Unfortunately passing the textfield through paramters would get really uncomfortable as I'd have to pass this textfield as an argument in every new object I create aswell - and in the logging funtion itself.
Tom
+1  A: 

Create a new Logging class and have that class have a static constructor. Add your logging method to this class. Make the static constructor save the logging field to a private variable. Now before you call the logging method just call your static constructor with the input field you'd like to use. This will create the class, set up the input field as the destination, and now you can simply just call the log function from anywhere.

Nicholas
I'm getting error 1026 when I try to make a constructor static.
Tom
+2  A: 

Essentially you need:

  • somewhere to log a message which is globally accessible
  • the ability to update a text field whenever the log message changes

A simple solution using objects could look like this:

Example

package {
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.events.Event;

    public class Example extends Sprite {
     private var messageLog:TextField;

     public function Example() {
         createTextField();
         MessageLogger.getInstance().addEventListener( MessageLogger.LOG, handleMessageLoggerUpdate );
         MessageLogger.getInstance().log( "Message!" );
     }

     private function handleMessageLoggerUpdate( event:Event ):void {
         messageLog.text = MessageLogger.getInstance().getLog();
     }

     private function createTextField():void {
         messageLog = new TextField();
         addChild( messageLog );
     }
    }
}

MessageLogger

package {
    import flash.events.EventDispatcher;
    import flash.events.Event;

    public class MessageLogger extends EventDispatcher {
     private static var instance:MessageLogger;
     public static function getInstance():MessageLogger {
         if ( !instance ) {
       instance = new MessageLogger( new InstanceKey() );
         }
         return instance;
     }

     public static var LOG:String = "MessageLoader#log";

     private var messageLog:String;

     public function MessageLogger(key:InstanceKey) {
         messageLog = "";
     }

     public function log( message:String ):void {
         messageLog += message;
         notify();
     }

     public function getLog():String {
         return messageLog;
     }

     private function notify():void {
         dispatchEvent( new Event( LOG ) );
     }
    }
}
class InstanceKey {}

The important thing here is that a message can be logged from anywhere using

MessageLogger.getInstance().log( "Your Message Here" );

and anything can be notified of when a message has been logged using

MessageLogger.getInstance().addEventListener( MessageLogger.LOG, listenerFunction );

at any point the current message log can be obtained using

MessageLogger.getInstance().getLog();
t3hh00d
I don't understand. What is making the textfield you created accessable everywhere?
Tom
The text field is not accessible anywhere, but the message logger is. The message logger also dispatches an event when a message has been logged. So anything, anywhere, can be notified and display the message log however they want, including just displaying the message log in a text field.
t3hh00d
I don't want to re-create the textfield for every object, so that won't fit.
Tom
Why would you have to re-create the text field for every object?
t3hh00d
Or pass it's reference through every object's parameter, sorry. I updated the first post with what I tried so far.
Tom
You wouldn't have to pass a reference either. All you would have to do is listen for an event where ever the text field exists and update it's text with the contents in the MessageLog. It's actually a pretty simple and straightforward solution to your problem.
t3hh00d
Ah, alright. Thanks. PS. would there be a way to avoid the need of getInstance(), maybe add it as an constructor or something?
Tom
Hm, yeah. Really you could do whatever you want with it. This solution is actually a pretty common design pattern called Singleton and so I followed the terminology that goes along with it. If you leave the name chances will be better that someone unfamiliar with this particular code will be able to recognize what is going on and feel comfortable modifying it in the way that they need.
t3hh00d
Alright. I'm also pretty confused about the "MessageLoader#log" - it has something to do with the event triggering. But what exactly, it must have somekind of meaning?
Tom
It's just a convention I use to avoid conflicts with other people's event types. If multiple events exist with the type "log" there could be errors. Using my convention just ties the event to the class by way of namespace conventions. Most event types will be defined like this: com.package.Event#eventType. Hope that helps.
t3hh00d
Nice. Thanks t3hh00d.
Tom
Anytime! Good luck.
t3hh00d
A: 

In your updated post the debug text field needs to be added to the display list somewhere. Right now it looks like it is just created and used during that log method. You add display objects to the display list by calling addChild( displayObject:DisplayObject ):Boolean; on a DisplayObjectContainer that is already a child of stage.

t3hh00d
I know. I quote from myself:"When I do an addChild(debugField) after creating it, it gives me error 1180."
Tom
Where are you calling addChild from? addChild is a method of DisplayObjectContainer so if you're calling it from within the static log method you are probably going to get a possibly undefined method error. Something that is already a child of stage is going to have to addChild debugField from outside the Logger class.
t3hh00d