CMXtraneous: Flash

Right on the edge of useful

Easy Fix to an Apparently Common FlashPaper 2 Issue

Posted Monday, January 29, 2007 8:26:11 PM by David Stiller

David Stiller

FlashPaper 2 was arguably, at one point, a competitor with Adobe Acrobat.  I’m not suggesting this was Macromedia’s intent, back in the day — maybe it was, maybe it wasn’t — and now that Adobe owns the lot, the discussion is moot.  In a nutshell, FlashPaper 2 converts documents into PDFs (just like Acrobat does, but with far fewer options), and it also converts documents into SWFs that “read” like PDFs.  They can be paged, searched, printed, and so on.  Neat concept, nicely executed.  I wouldn’t say these SWFs have especially caught on, but that’s fine … I use FlashPaper 2 in certain cases, and because it’s so pared down, the app loads much quicker than Acrobat.  That makes it an easy choice for no-frills PDF conversion.

FlashPaper 2 is available both as a stand-alone product and bundled with Studio 8.  On Windows, the Studio 8 version suffers a technical issue, apparently fairly common, in that it fails when used as a printer (as in, File > Print, and choose FlashPaper 2 as the print device).  Sure enough, when I re-installed Studio 8 after a recent hardware issue (completely unrelated), I could no longer create FlashPaper SWFs by printing to the app.

It didn’t take me long to find a solution, but it’s one I would never have thought to attempt.  Without further ado, then, for anyone who has suffered the same fate, here it is:

  • Open your Command Prompt (Start > Run… type “cmd” without quotes and click OK).
  • Type cd C:\Program Files\Macromedia\FlashPaper 2\i386, then press Enter.  (Note, your mileage may vary, here.  Just make sure this ends up in the i386 folder of your FlashPaper 2 installation folder.)
  • Type ..\fpdriversetup.exe -ui, then press Enter.  This invokes the fpdriversetup.exe executable in the parent folder with the -ui switch.  What it does is reinstall FlashPaper 2’s printer driver … and whatdya know, it works!

Thanks to the Adobe support forum user who goes by the name miss-n-me.  Your sleuthing helped me out!

Category tags: Flash

Sound.position "Gotcha" with Multiple Calls to Sound.loadSound()

Posted Tuesday, January 23, 2007 10:41:53 PM by David Stiller

David Stiller

The Sound.position property indicates how far along a Sound instance has played.  If you’ve loaded an external file or attached an embedded file at runtime, but haven’t yet started it, that instance’s position property is 0.  If it’s a 10-second clip and you’re 2.5 seconds in, the property reads 2500 (that’s 2,500 milliseconds).  When your audio reaches its end, position will match that instance’s Sound.duration property, which indicates the total length of the audio.  This is a can be useful for checking when a sound has concluded — of course, the Sound.onSoundComplete event is much more straightforward — but there are any number of reasons you might want to keep tabs on a sound’s position.  Unfortunately, this property doesn’t always report the value you may expect.

The Sound.loadSound() method loads audio files (specifically MP3s) that are external to the SWF.  This method takes two parameters.  The first indicates the location of the MP3 file; the second is optional and determines whether or not the audio plays in stream mode.  The word is a bit misleading in this context, because loaded files don’t truly stream unless served by streaming server software, such as Flash Media Server.  If simply loaded from the server’s file system, the MP3 will progressively download, which means it can begin playing before the entire file has been retrieved.  Comes in handy.  :)  The problem is, any subsequent call to loadSound() — for the same instance — leaves the position value where it was at the time the call was made.  Personally, I would expect it to start again from zero, because the new file starts from the beginning (when enough of the file has loaded).

In other words, in the following code …

var song:Sound = new Sound();
song.loadSound("looneyTunesTheme.mp3", true);

… the specified MP3 starts playing as soon as enough of the file has arrived.  If you monitor song.position, you’ll see it grow from zero until the end of the song.  If you happen to load a new file at, say, seven seconds in …

setTimeout(function():Void {
  song.loadSound("tronTheme.mp3", true);
}, 7000);

… the instance’s duration value will change — assuming each song has a different length — but its position value will keep trucking from 7000 onward.

Play this new song for several seconds, then jump back …

setTimeout(function():Void {
  song.loadSound("looneyTunesTheme.mp3", true);
}, 45000);

… and position just keeps climbing.  The only thing that stops it is the end of the audio.  When position’s value reaches the duration value of the currently loaded file, position plumb stops updating, even if the file continues to play.  Remember, this isn’t because position is actually the same as duration:  because of several seconds of the other MP3 playing, the position property was thrown off.

I’m not even sure if this phenomenon is a bug or a feature, to be honest.  Regardless, is there a way to “fix” it?  The answer is yes.

Just before you issue a second (or third, etc.) call to loadSound(), be sure to call Sound.start() first, and pass in the optional secondsOffset parameter.  That resets position.

// … existing code
song.start(0);
song.loadSound("aintNoMountainHighEnough", true);

Category tags: Flash

setTimeout() "Gotcha" in Class Files

Posted Tuesday, January 16, 2007 8:27:19 AM by David Stiller

David Stiller

The setTimeout() function is a valid citizen in the realm of ActionScript 2.0; it was simply left off the roster for some reason, so you won’t find it in the documentation.  It works very much like its JavaScript counterpart and is less cumbersome to use than setInterval() for triggering a single delayed action.  You can reference setTimeout() just fine in timeline code, but I found an unexpected problem when employing this function in a class file.  Its presence halted the compile process and caused all sorts of misleading errors, such as the idea that Stage can’t be reference in a class file (it certainly can).  Is there a workaround?  Yes.

An answer, short and sweet

If you find yourself desiring setTimeout() inside a custom class, use the array access operator to refer to the function.

_global["setTimeout"]

This one of the techniques you can use to reference objects dynamically — and even functions are objects.  To actually trigger the function, you need to add the parentheses, and those come right after the closing bracket.  At that point, it’s business as usual.

_global["setTimeout"](functionToTrigger, 1000);

How it works

To be honest, I can’t explain the “how” especially well, in this case.  The setTimeout() function was left out of the documentation and the intrinsic class definition files, which means the compiler (sometimes) doesn’t know it exists.  Why this only happens in external class files is beyond my grasp.  But the solution is easy, enough.  :)  I had to experiment with which object to use as the prefix (I tried _root, a passed-in reference to the main timeline, and this, but suddenly _global occurred to me, and that’s what works).

Category tags: Flash

A Tip on the Boolean() Function (Casting as Boolean)

Posted Tuesday, January 09, 2007 2:00:50 PM by David Stiller

David Stiller

When you load data from XML or text files, or retrieve values from the TextField.text property, the information you get is a string.  Even if the incoming value is, say, the numeral 3 (without quotes), it’s a string when evaluated by ActionScript.  Even if the value is “false” (with or without quotes), it’s a string — not a Boolean — and may appear to ActionScript as true!  Whoa!  That could cause a few problems.  In the case of numbers, there’s an easy way to tell ActionScript what the datatype should be, and it’s called casting.  You may cast a string numeral into an actual Number datatype by using the Number() function.  With a text field whose instance name is money

var looseChange:Number = 0;
looseChange = Number(money.text);

That converts the value of the money.text property to a true number, which you can verify with trace(typeof(looseChange)); — but the Boolean() function handles things differently.

In ActionScript, false is synonymous with 0 and true is synonymous with every other number.  If you cast the number 0 as Boolean, you’ll see false in the Output panel.

var num:Number = 0;
trace(Boolean(num));

Same goes for any other number, except the output will be true.

var numA:Number = 1;
var numB:Number = 2;
var numC:Number = 1000;
trace(Boolean(numA));
trace(Boolean(numB));
trace(Boolean(numC));

But strings … those are different.  Since Flash Player 7, when the Boolean() function sees a string, it counts the number of characters in that string.  If the string is empty (zero characters), the cast resolves to false.  A count of one or more characters resolves to true.

var strA:String = "0";
var strB:String = "1";
trace(Boolean(strA));
// outputs true, even though the string was 0
trace(Boolean(strB));
// outputs true, but not because the string was 1

Even the strings “true” and “false” both resolve to true, because they contain one or more characters.

So, is how can text values be cast as true Booleans?  Well, you can either write your code to abide by the rules as they are — that is, make sure your XML file contains empty strings for false and non-empty strings for true — or use a conditional statement.

var str:String = "false";
var boo:Boolean;
if (str == "false") {
  boo = false;
} else {
  boo = true;
}

Or, to be more compact about it, use the conditional operator:

var str:String = "false";
var boo:Boolean = (str == "false") ? false : true ;

Category tags: Flash

Simplify: Use Boolean Expressions Creatively

Posted Wednesday, January 03, 2007 8:11:18 PM by David Stiller

David Stiller

I was coding up a slideshow this afternoon for a quick demonstration to a client.  In the end, much of today’s “rough draft” ActionScript will be converted into a custom SlideManager class.  For the time being, though, my “jump in and throw something together” approach was helpful anyway, because it brought to mind a number of features the client is going to ask about — I’d bet money on it — and now I’ll be prepared.  In addition, it reminded me of an admirable principle in programming:  elegance.

This entry is more of a “think about it in broad terms” tip than the usual “type this ActionScript, exactly.”  Here’s the situation.  I had just finished writing a set of functions to advance the slideshow.  They were called previous() and next().  I had already stored a number of slide objects in an array (these will eventually be instances of a Slide class).  The first thing the next() function does is check if the current slide is less than the total number of slides.  If it is, then the slideshow hasn’t yet reached its end, which means the “next” button can remain active.  If it isn’t, then the slideshow has reached its end, and the “next” button needs to be disabled.  This includes disabling any event handlers associated with it, dimming it (graying it out), and a handful of other things.  At first, I handled this with an if statement.  Makes sense, right?

function next():Void {
  if (currentSlide < slides.length – 1) {
    // still going
  } else {
    // reached the end; disable
  }
}

The if statement checks the value of a currentSlide variable against the value of the Array.length property a particular slides array.  The part at the end that substracts one is there because arrays start at zero, rather than one.  In an array of three items, the array’s length is 3, but its elements run from 0 through 2.

I had already written a class called NavigationButton, which features an active property.  I coded active to be similar in principle to MovieClip.enabled or Button.enabled:  set it to true and the button is active; set it to false, it disables, automatically dims, and does the other things it needs to.  So that if statement above could have been written like this (and, in fact, was).

function next():Void {
  if (currentSlide < slides.length – 1) {
    btnNext.active = true;
  } else {
    btnNext.active = false;
  }
}

Still makes perfect sense.  When the slideshow is over, deactivate the button; otherwise, leave it active.  But then I saw the correlation between the true/false nature of the if statement and the true/false nature of the active property.  Suddenly, I saw where I could collapse those lines into something neater, more elegant.  I rewrote it like this:

function next():Void {
  btnNext.active = (currentSlide < slides.length - 1);
}

See why that works?  The expression currentSlide < slides.length – 1 hasn’t changed.  It’s purpose is to get that if statement to make a decision, either true or false, which is all an if statement ever does anyway.  That expression resolves to either true or false, and since the NavigationButton.active property takes a Boolean value, the expression can be used to actually set the property, rather than steer an if statement toward doing the same thing.

NSurveyor, who often comments on my developer blog, uses this sort of “trick” more than anyone I know, often to great effect.  When it reduces the number of lines you have to type, it’s a terrific practice.  Of course, it also has the potential to make code more difficult to read, especially to someone who wasn’t present when you wrote it, so weigh the pros and cons before going nuts with it.  But it sure it neat to “fold” several lines into one!

Category tags: Flash