induce error for debugging purposes? - actionscript-3

Hypothetically, I have a switch that has 437 cases. I've identified every possible case (I think), and each is handled.
I'm worried that I missed # 438, and want something in the Default to alert me of this.
I could put a
trace("ERROR! Stackoverflow has detected your ginormous gaffe and suspended your account indefinitely!");
in there, but I'm worried that this error will occur 7 weeks from now and the trace will be lost among all of my other silly warning traces. I've considered having my Default do this:
trace(myArray[-1]);
which would surely(?) give an error and stop the program, alerting me to my hideous oversight, but am wondering if there isn't some better, smarter way to go about detecting a possible error like this.
Anyone? Bueller?

Why not to throw an error?
default:
throw new Error("Default reached");

The first option is to throw an exception:
throw new Error('Exception!!!')
but you wont get anything if you don't have debugger flashplayer
Another way is to show a popup:
In case you use flashplayer in browser:
ExternalInterface.call("alert", "Exception!!!");
In case you use Flex Framework:
Alert.show('Exception!!!')
You could try to highlite it somehow:
trace( "==========================================\n" +
"==========================================\n" +
"==========================================\n" +
"===============Exception!!!===============\n" +
"==========================================\n" +
"==========================================\n" +
"==========================================\n" +);
And the last option is a custom popup:
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
const theStage:Stage = MovieClip(root).stage;
const tf:TextField = new TextField();
tf.text = "Exception!!!";
tf.autoSize = TextFieldAutoSize.LEFT;
tf.x = theStage.stageWidth - tf.width >> 1;
tf.y = theStage.stageHeight - tf.height >> 1;
tf.border = true;
tf.addEventListener(MouseEvent.CLICK, function(e:MouseEvent){
e.currentTarget.parent.removeChild(e.currentTarget);
})
theStage.addChild(tf);

Related

Issues with SharedObject?

So, simply put, I am trying to use the SharedObject to simply hang onto a variable for me that I need to save for the user to remember an option choice. Nothing dramatic, but for some reason, no matter what I do, I cannot seem to actually create the SharedObject to interact with it in the following lines, I am running traces every step to just keep an eye out for where it is breaking, and the OBJ SET trace will run, but if I try to access the SortObject in anyway through .data, it just seems to not work? This is my first time messing with SharedObjects, and I am still pretty new to AS3 and since its an ailing platform to begin with, I cannot seem to find any reason for this to be failing? Every use of the 100 uses I have seen in action seem to use it in the same manner I do?
I am not throwing any compile errors as a result either.
From what I can tell, the SharedObject is simply not being created for some reason.
public function ChangeSortSetting(event:Event) : *
{
var SortTypeSetting = event.target.name == "SortTypeSet";
var ExtraSetting = event.target.name == "ExtraSet";
trace(" VAR SET ")
var SortObject:SharedObject = SharedObject.getLocal("SortObject")
trace(" OBJ SET? ")
if (SortObject.data.SortMethod == null)
{
SortObject.data.SortMethod = "alpha"
SortObject.flush()
}
trace(" / 1UIX / OBJ TRACE CHECK / " + SortObject.data.SortMethod)
}
You can not change the event name .
The problem is in those lines below .
var SortTypeSetting = event.target.name == "SortTypeSet";
var ExtraSetting = event.target.name == "ExtraSet";
Try changing to :
var SortTypeSetting = "SortTypeSet";
var ExtraSetting = "ExtraSet";

1120 Access of undefined property Ibar & Ipc

stop();
import flash.display.*;
this.stop();
this.loaderInfo.addEventListener(ProgressEvent.PROGRESS, PL_LOADING);
function PL_LOADING(event: ProgressEvent): void {
var pcent: Number = event.bytesLoaded / event.bytesTotal * 100;
lbar.scaleX = pcent / 100;
lpc.text = int(pcent) + "%";
if (pcent == 100) {
this.gotoAndStop(2);
}
}
You'll do well to enable "Permit Debugging", however, the issue is on lines 14 & 15. It means you don't have an object in memory by those names. If you're working in the Flash IDE, and these are symbols in your library, add them to the stage, the and issue will be resolved.
Well, this code structure looks a bit disorganized. I'm not sure whether a lot of these changes will matter (since I currently don't have access to flash), but here is how I would typically write this:
stop();
import flash.display.*;
//no need for this.stop() if you've already stopped
this.loaderinfo.addEventListener(ProgressEvent.PROGRESS,PL_LOADING);
function PL_LOADING(e:ProgressEvent):void{
//possibly part of the problem is that the var keyword was on the wrong line
var pcent:Number = e.bytesLoaded/e.bytesTotal*100;
ibar.scaleX=pcent/100;
ipc.text=String(int(pcent)+"%");
//typically you want to make it clear that it's a string when dealing with text fields
if(pcent==100){
gotoAndStop(2);
}
}
Small changes like these as well as thoughtful organization could save your code. If you're still having problems with your code just notify me and I'll try to help you out.

How do I show the save progress of a FileStream in Flex?

I'm making a simple tool that will let the user eventually save a image to the disk.
To make this, I'm using the FileStream class and its writeBytes() method.
This is working nicelly. The problem occurrs when I tried to show the save progress with a simple mx:ProgressBar. I've tried some approaches, but none seems to work.
Here is the ActionScript piece of code:
private function save(file:File, image:MyImageClass):void {
var data:BitmapData = new BitmapData(width, height, true, 0x000000);
image.draw(data, _cols);
var bytes:ByteArray = new PNGEncoder().encode(data);
fileStream = new FileStream();
fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onProgress);
fileStream.addEventListener(Event.CLOSE, onClose);
try {
fileStream.openAsync(file, FileMode.WRITE);
fileStream.writeBytes(bytes);
} catch (e:Error) {
Alert.show("Error trying to save the image: " + e.message);
} finally {
fileStream.close();
}
}
private function onProgress(event:OutputProgressEvent):void {
var progressRatio:Number = (1 - (event.bytesPending / event.bytesTotal));
progressBar.setProgress(progressRatio, 1);
trace(progressRatio);
if (event.bytesPending == 0)
event.target.close();
}
private function onClose(event:Event):void {
trace("closed");
}
And the mxml for the progress bar:
<mx:ProgressBar id="progressBar" mode="manual"/>
Executing this I got a frozen interface that is released when the file is totally saved and on the console I get all the traces at the same time. The progress bar stays on 0% until the interface is unfrozed and it goes to 100%.
I know that Flash is single thread, but I thought that the FileStream.openAsync() method should do the dirty work to make my interface responsible. It shouldn't be that hard to do this simple and (I think) common task.
The question is: what I'm doing wrong?
Thanks in advance
How big is the file being saved?
You code seems fine, in terms of saving the file. However, what I suspect is actually taking a long time is encoding the file to PNG format. Unfortunately, the PNGEncoder doesn't dispatch any progress events. But you should check out this project from Lee Burrows, or consider using Actionscript Workers to do the encoding in a different thread.
Quick way to prove it: add trace statements before/after you encode to PNG. Does the big delay correspond to this phase, or to the actual save?
If that doesn't help, please specify how big your file is, and whether you getting 0, 1, or multiple OUTPUT_PROGRESS events.
I agree with Sunil, but I'd like to add a thing or two.
First of all I'd suggest using the new method of the BitmapData class for encoding an image, because it's faster and easier. So your code would change to something like this:
var data:BitmapData = new BitmapData(width, height, true, 0x000000);
image.draw(data, _cols);
var bytes:ByteArray = data.encode(data.rect, new PNGEncoderOptions());
You can track the progress of the writing the file (although I suspect this isn't taking much time, like Sunil said) like this:
bytes.position = 0;
while(bytes.bytesAvailable > 0) {
fileStream.writeByte(bytes.readByte());
trace("progress:", bytes.position / bytes.length * 100); // multiply by 100 for percentage
}
Please note that you'll need a worker for this approach, else the progress will only update visually when the save is done.
Sunil is correct. Writing the file hardly takes a moment. It's decoding the byte array that's blocking the application. I implemented the following code to test it out.
private function save(file:File):void
{
var bytes:ByteArray = new ByteArray();
//233348 - very fast (requires 6000 x 10000 bitmap pixels)
//252790 - very fast (requires 6500 x 10000 bitmap pixels)
//2488990 - need a whole magnitude more of data in order to show the progress messages
for (var i:int = 0; i < 2488990; i++)
{
bytes.writeByte(1);
}
var fileStream:FileStream = new FileStream();
fileStream.addEventListener(OutputProgressEvent.OUTPUT_PROGRESS, onProgress);
fileStream.addEventListener(Event.CLOSE, onClose);
try {
fileStream.openAsync(file, FileMode.WRITE);
fileStream.writeBytes(bytes);
} catch (e:Error) {
//Alert.show("Error trying to save the image: " + e.message);
} finally {
fileStream.close();
}
}
You're going to need a progress indicator on the decoding task rather than on the file writing task. Workers seem like the best solution to this, but it depends upon which version of the runtime you need to target.

ActionScript 3.0 Error #1010 - preloader function

I am a Flash and ActionScript newbie. I am trying to follow a video tutorial to make a preloader and I'm having a problem that the video didn't seem to address. I believe I have entered in all of the code correctly from the video. This is it:
stop();
addEventListener(Event.ENTER_FRAME, loaderF);
function loaderF(e:Event):void{
var toLoad:Number = loaderInfo.bytesTotal;
var loaded:Number = loaderInfo.bytesLoaded;
var total:Number = loaded/toLoad;
if( loaded == toLoad ){
removeEventListener(Event.ENTER_FRAME, loaderF);
gotoAndStop(2);
} else {
preloader_mc.preloaderFill_mc.scaleX = total;
preloader_mc.percent_txt.text = Math.floor( total * 100 ) + "%";
preloader_mc.ofBytes_txt.text = loaded + "bytes";
preloader_mc.totalBytes_txt.text = toLoad + "bytes";
}
}
What I typed in doesn't generate a compiler error, but the output tells me:
TypeError: Error #1010: A term is undefined and has no properties.
at preloader_fla::MainTimeline/loaderF()
And since I really don't have any experience outside of what I'm learning from this tutorial series, I don't know what to do to fix this.
I don't use Flash CS5, but you should be able to get the line # for where the error is occurring, I believe, by executing the SWF by pressing CTRL+SHIFT+ENTER.
Once you get the line number, you should see that something on that line is null or not defined. The error says it occurs in the function loaderF(), and looking at that code the only place such an error could occur is in the else block:
} else {
preloader_mc.preloaderFill_mc.scaleX = total;
preloader_mc.percent_txt.text = Math.floor( total * 100 ) + "%";
preloader_mc.ofBytes_txt.text = loaded + "bytes";
preloader_mc.totalBytes_txt.text = toLoad + "bytes";
}
In the above code block, one of these things is not defined:
preloader_mc.preloaderFill_mc,
preloader_mc.percent_txt,
preloader_mc.ofBytes_txt,
preloader_mc.totalBytes_txt
Maybe your preloader movie clip is missing one of these objects...
First, you'll want to turn on debugging found under (File > Publish Settings > Flash (.swf) > Permit Debugging). This will provide line numbers and allow additional debugging to help track down errors.
Secondly, in the code sample you've provided, you haven't declared a loader, so when you call on loaderInfo, it makes sense that flash complains about "a term is undefined". Although, technically, the loaderInfo object is a child of the event object. Thus, loaderInfo.bytesTotal would become e.loaderInfo.bytesTotal, assuming you added the event listener to the loader object; currently yours is added to the timeline.
Bookmark Adobe's Actionscript 3.0 Reference. Use it. As you begin your journey in Flash, this will be your indispensable handbook to speaking AS3. Specifically, you'll want to refer to the Loader class.
Here's what you're likely missing in your code:
var myLoader:Loader = new Loader();
myLoader.load(new URLRequest("path/to/my/file"));
Your function loaderF is being called during every frame update to the screen (likely every .034 seconds). You'd probably be happier with ProgressEvent.PROGRESS instead of Event.ENTER_FRAME. If so, you'll also want to catch the complete event, and that'd look like this:
myLoader.addEventListener(Event.COMPLETE, loadComplete);
myLoader.addEventListener(ProgressEvent.PROGRESS, loadProgress);
function loadComplete(e:Event):void {
// Stuff to do when the file finishes loading.
}
function loadProgress(e:Event):void {
var current:int = e.bytesLoaded;
var total:int = e.bytesTotal;
var percent:Number = current/total;
// Update the readout of your loading progress.
}
Hopefully that points you in the right direction. :)

Adobe Air, packaged install fails with my trace routine... how come?

I cobbled together some code from here and there for a trace I like... it generates an error to get a stack trace and picks out the traced routine name, I like that detail in the trace log.
Problem: it fails in an installed AIR file. I wonder why? I don't expect it to do anything as is... just, I'd prefer it not cause the program to fail!
tx
artie
enter code here
static public function XTRACE( ... traceArgs ):void {
try {
throw new Error(); // make a stack
} catch (e:Error) {
var stack:String = e.getStackTrace();
var frames:Array = stack.split("\n");
var myFrame:String = String(frames[2]);
myFrame = myFrame.replace("\t", "");
// "at " can be followed by some part of the package
// you don't want to see. E.g., if your code is all in
// com.foo.bar, you can put "at com.foo.bar." so as not
// to crowd the display
myFrame = myFrame.substr("at ".length);
myFrame = myFrame.substring(0, myFrame.indexOf("["));
var now:Date = new Date();
trace(new Date().toLocaleTimeString() + ":" + myFrame + ": " + traceArgs.join(" "));
}
}
In what way is your app failing?
1) Trace routines are for debugging, so your trace won't do anything in an installed app.
2) I'm not sure when you call this routine, but it seems weird that you have a routine that only throws an error. I think in this code the 'catch' is only going to get entered if there's an error throwing the error. Normally you would try to perform some useful action, and catch errors when something goes wrong.
Within the trace function your attempting to invoke the Date().toLocaleTimeString() statically before it becomes instantiated by the new keyword. Try the following instead:
trace((new Date()).toLocaleTimeString() + ":" + myFrame + ": " + traceArgs.join(" "));
thanks for your input Fergal. The XTRACE function works fine running with the debug player, and fails only when running with the release player. So I assume the code line I use must associate values in the right order... I settled on using a function I didn't know about before:
enter code here
static public function XTRACE( ... traceArgs ):void {
if ( Capabilities.isDebugger ) {
With that, XTRACE does nothing unless it is executing in a debug environment. So it works around the issue. I'll still use your brackets though, I like to make order of association obvious too ;-)
I realize you've probably grown old and forgot what flash is since you asked this question. But, you're getting an NPE because e.getStackTrace() returns null in the release player.
A couple other things:
You don't need to throw the error to get a stack trace; new Error().getStackTrace() works fine.
Since this is debug code, and the calling code probably isn't expecting errors, you should wrap the whole thing in a try catch.
The compiler won't resolve 'at '.length, so it will be called every time at runtime. Unless you're really paranoid, you can just hard code it to 3.
Both the substrs can be combined into 1
The now variable isn't used.