Using Flash as GUI for Captivate E-Learning

Posted on: April 13th, 2012 by Edward 2 Comments

A while back I was given the task of creating an E-Learning courseware product. The product was to contain three separate courses, each with 10 modules and each module was to end with a quiz. On completing a course, the user could then take an exam…then, upon passing the exam, the user would then be able to print a certificate. Needless to say, the task had some inherited challenges, but how to incorporate this magnitude of information in a single interface…well, that was the rub!

After looking at Captivate’s Aggregator, I was quickly convinced this was not an option for my purpose…not mostly because the product had to be published as an EXE for CD/DVD ROM delivery, but there didn’t seem to be a way to aggregate Aggregator files…which was essentially what I needed to do.

Upon further usability inspection, I also needed the Captivate modules to seamlessly move from the end of the module to the following quiz to the next module to the exam and to the certificate…whew!

Not only that, the client needed the end-user to be able to insert the disc, use the product and then after quitting and removing the disc, have the user return to where they left off when they re-insert the disc again…the challenges just kept on coming…

After exploring my options, I came to the conclusion that I had to create an environment outside of Captivate and “load” what the user needed depending on what button was clicked…and of course, this meant using Flash.

This post is not a step-by-step tutorial, but insight on how I resolved certain issues that may just come in handy for someone else needing solutions via a similar scenario…

The first thing I needed to do was design the GUI (graphical user interface) to accommodate the courses, modules, quizzes, exams and certificates…not the scope of this post, however.

Once the designed of the GUI was complete (Photoshop), I then translated the design in Flash…making sure to “sync” the GUI frame rate to Captivate’s default frame rate; which is 30 fps and Flash’s default is 24 fps.

Next was the timeline labeling…product home page, three courses (home page for each), 10 modules each course, quiz after each module, exam after each course and then the certificate. Needless to say, the timeline got to be fairly long…mostly so I could see the “frame label” text (I find that very convenient).

Now, with my timeline set up, I could insert some test buttons that “moved” through the timeline sequentially so I could work the “return where user left off” issue.

So, in my Flash GUI, on frame one of my actions layer, I inserted this code:

//resume from exit frame sharedobject
var appExitFrameSO:SharedObject = SharedObject.getLocal
("appExitFrame");
if (appExitFrameSO.data.exitFrame == null) {
 gotoAndStop("fl_intro");
  }else{
 var gotoExitFrame = appExitFrameSO.data.exitFrame;
 gotoAndStop(gotoExitFrame);
}

…then for each frame label, I put a key frame on my actions layer and inserted this code:

//save currentFrame to SO
var ssHomeSO:SharedObject = SharedObject.getLocal("appExitFrame");
ssHomeSO.data.exitFrame = currentFrame;
ssHomeSO.flush();

The “ssHomeSO” is the variable (var) name and it must be unique each time its used to avoid compile errors.

…and for those who don’t ActionScript, my code does two things…first, it DOES NOT use an addEventListener…this means that it IS NOT constantly running (i.e. “listening”) in the background and slowing down the application…the other thing, is it ONLY writes the frame number to the SharedObject (Flash cookie) when the user exits the application…

Okay, so now I could burn my GUI to a CD, exit at any point and return to that same point upon re-inserting the disc.

Next, I needed to “load” Captivate SWFs into my GUI (module, quiz or exam)…so, I created my Captivate files with just some identifier text on slide one, exported them as SWFs and used this code:

//----------- LOAD EXTERNAL SWF ---------------//
//----- and of course the blue text is the SWF that is being loaded
var load_ssHome:Loader = new Loader();
var url_ssHome:URLRequest = new URLRequest("Courses/ss/ssHome.swf");
load_ssHome.load(url_ssHome);
addChild(load_ssHome);
load_ssHome.x = 0;
load_ssHome.y = 154;
//----------- UNLOAD EXTERNAL SWF ------------//
var frame_ssHome:uint = this.currentFrame;
addEventListener(Event.ENTER_FRAME, loaded_ssHome);
function loaded_ssHome(evt:Event):void {
     if(this.currentFrame != frame_ssHome) {
   if(contains (load_ssHome)) {
              this.removeChild(load_ssHome);
     load_ssHome.unloadAndStop();
   }
  }
}

And again, the variable names MUST be unique…basically, I used an underscore (_) and the frame label name to ensure consistency…i.e. “load” bacame “load_ssHome” and so on…

…now some explanation on the code…first, the code has to adjusted for each “loaded” SWF so a naming convention was established, but basically, the ActionScript loads the Captivate SWF, and then, when the user clicks a button to leave the current frame, the ActionScript then does an “unloadAndStop” which not only unloads the loaded Captivate SWFs, but any audio or video associated with it…THIS IS VERY IMPORTANT!

Without the “unloadAndStop” any audio associated with the Captivate SWF would continue to play even when a different Captivate SWF was loaded…NOT GOOD!

Its important to note that “unloadAndStop” is a feature of Flash Player 10…if you are publishing to an older player, this will not work.

Now, we get to a tricky part…all the buttons I used to test the “where you left off” feature were now replaced with Captivate SWFs…this meant that the buttons must now go into the Captivate SWFs and move the playhead in the main Flash timeline…YES, you read that correctly…a button in the Captivate SWF would need to move the playhead in the main Flash timeline.

This turned out to be quit the up hill battle…and seemingly such a little thing…and posting on many Flash “and” Captivate forums couldn’t get this working for me…but one reply came came close…and after experimenting with that code, I came up with this code:

//This code works with SWF button imported into a Captivate
//project as an animation
//in order to move Flash MAIN timeline
btn_goToHome.addEventListener(MouseEvent.CLICK, goClickMe);
function goClickMe(event:MouseEvent):void {
 MovieClip(parent.root.parent.root).gotoAndStop("fl_rHomePage");
}

This code works because Captivate SWFs have their own timeline (i.e. parent.root); so, in order to get to the Flash GUI “main” timeline which “is” the “parent” of the Captivate SWF, I needed to include a second “parent.root” to the button code.

And the same FLA file can be used for creating all the buttons since the buttons are published as individual SWFs; the button and function names don’t need to change; only the destination/location you need the Flash GUI play head to “gotoAndStop”—i.e. a frame label name in my case.

Now, I’m sure some ActionScript guru out there will find plenty of fault in how I resolved my issues and since I’m not an ActionScript guru I fully expect some harsh replies…but the damn thing WORKS…and at the end of the day, that’s an important consideration!

ADDITIONAL TIDBITS

Although I had the Flash GUI keeping track of the main timeline, the timeline of the Captivate SWFs were an entirely separate issue. Now, Captivate does have this functionality built-in, but there’s no way to edit what it looks like…so, I found a widget at http://www.cpguru.com/ with this functionality and the author created the widget for me with my design—for a small fee of course.

I’ll probably put this in a separate post, but here is the code I put on a Flash button, imported as an animation that when clicked, allows the user to save the current SWF frame as a JPEG…I needed this for my certificate…this way, the user could print, archive and send to client as proof of passing the exam.

SAVE FLASH AS JPEG

//you must download and put the JPG and PNG encoders in your
//script folder in order for this code to work
import com.adobe.images.JPGEncoder;
import com.adobe.images.PNGEncoder;
function onSavePictureButtonClicked(event:MouseEvent):void
{
 var bitmapData:BitmapData = new BitmapData(stage.stageWidth,
 stage.stageHeight); bitmapData.draw(stage); 

 var jpgEncoder:JPGEncoder = new JPGEncoder(100);
 var byteArray:ByteArray = jpgEncoder.encode(bitmapData);
 byteArray = PNGEncoder.encode(bitmapData);

 var fileReference:FileReference = new FileReference();
 //Certificate.jpg is what is being saved…
 //change this to whatever your
 //DEFAULT file name to be, just don't leave it blank
 fileReference.save(byteArray, "Certificate.jpg");     
}
// Add button handler
btn_save.addEventListener(MouseEvent.CLICK,
onSavePictureButtonClicked);

I hope this post can help other E-Learning developers faced with the same scenario…and although it was farily LONG, I tried to make it easy to understand, but if something was unclear, please let me know and I’ll try to clarify.

2 Responses

  1. Edward says:

    Cesargy, for my post…the apps I’m using are Flash Pro CS5 and Captivate 5.5…also, the Flash Player is ver 10.

    The interface is Flash that loads the Captivate SWFs…however, the buttons are authored in Flash…published as a SWF and INSERTED into Captivate as an animation…this is so the Captivate SWF can be UNLOADED from the Flash interface. If your project is not setup the same way…you will have problems.

    Also, it seems like you are saying that you have a Captivate SWF loading a Captivate SWF…if that’s the case, you’re doing something that’s not recommended.

    However, if that is what you want to do, there’s a Loader Widget at http://www.cpguru.com that may be useful…I know it is available but I’m not really sure of the scope of usage…

  2. cesargy says:

    Hi Ed, really cool post, but I’m having troubles unloading Captivate SWFs created with Captivate 5.5, I’m using the unloadAndStop method but it seems is not working but when I do the same with Captivate 4 SWFs (as2) is working perfect, is there anyway to close or unload this kind of SWFs?

    In the other hand the close button in the Captivate SWF don’t dispatch any event? because y click it in your files but i see no message

    Well thanks and once again Really cool post!!!

Leave a Reply

You must be logged in to post a comment.