Last week we looked at what it takes to score a Question Widget. While this is really the only thing you need to know in order to make a ‘working’ Question Widget, there’s a lot more involved in making a complete Question Widget.
What’s a ‘complete Question Widget’ you ask? That would be a question widget that for all intents and purposes works just like a native Captivate Question type. A widget that when Captivate says: “Jump!” It knows exactly how high. And the first step to building one of these, is to have your question enable and disable at the right times.
When is a Question Enabled and When is it Disabled?
A Question is enabled when the user should interact with it; it is disabled when they shouldn’t.
So when the audience is in the process of answering the question, the question is Enabled.
After the user clicks the submit button (or the widget submits the question using the triggerSubmitProcess() method) there is a slight pause before moving to the next slide to give the audience time to look over how they answered the question and what the success or failure caption says. During this period the audience can’t interact with the question. Which is good, because if they did it might make them wonder if what they just did changed how question was answered. So at this point the question is Disabled.
When the audience reviews the quiz, once again we don’t want them to think that they can change their answer. So the question is Disabled.
Then again, sometimes the audience is allowed the opportunity to retake the quiz. In this case the question must be reset and the audience allowed to answer again. So now the question is Enabled.
As you can see, working out when your question needs to be enabled or disabled can be quite mind bending. I’m not entirely sure if I’ve even noted every enabling/disabling circumstance above. The good news is, you don’t need to know exactly when the question is being enabled or disabled, because the good developers at Adobe have already sorted that out for us with two Template Methods. enableAnswers() and disableAnswers().
enableAnswers() is called whenever the question should be enabled, disableAnswers() is called whenever it should be disabled. These two functions compliment each other like yin and yang. Theoretically if you call enableAnswers() then disableAnswers() right afterward, they should cancel each other out. Or, from a programming standpoint, enableAnswers() is where you add your mouse or keyboard listeners, and disableAnswers() is where you remove them.
So where does enterRuntime() come into the mix? You should use enterRuntime() to add the question’s visual elements to the stage (or, alternatively, grab them off the slide) and store them in variables or arrays or whatever you’re using. But you don’t add your event listeners there, that’s what enableAnswers() is for. Depending on the question, you might set dispatchRuntimeAfterRewind to false, because enableAnswers() can reset the question when it’s rewound.
Show me the code
enableAnswers() and disableAnswers() are used just like any other Template Methods. That is aside from one thing: They are public, not protected like most methods.
1 2 3 4 5 6 7 8 9 | override public function enableAnswers():void { } override public function disableAnswers():void { } |
I know, I know, it’s inconsistent and user unfriendly, but these methods are called directly from Captivate and it can only do that if they’re public.
Time for an example! Let’s say you had a question widget where all you did was drag around a circle. You’d need to make sure you could only drag the circle when the question is enabled. Here’s how you’d build that question.
Note: Because we’re focusing on enabling and disabling, I have made it so that this question will always be answered incorrectly. This means we can see if it still works when retaking the quiz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | package { import flash.display.Sprite; import widgetfactory.QuestionWidget; import flash.events.MouseEvent public class SimpleCircleQuestion extends QuestionWidget { // The circle we're going to drag around screen. private var circle:Sprite; override protected function enterRuntime():void { // Create circle. circle = new Sprite(); addChild(circle); // Draw the circle. circle.graphics.beginFill(0xFF0000); circle.graphics.drawCircle(0, 0, 25); circle.graphics.endFill(); // Make sure we don't draw the circle again if the user rewinds the movie. dispatchRuntimeAfterRewind = false; // The question will always answer as incorrect so that we can test with retake quiz. isCorrectAnswer = false; } // Captivate wants the interactivity on. override public function enableAnswers():void { circle.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); circle.addEventListener(MouseEvent.MOUSE_UP, onMouseUp); // Make hand cursor appear when rolling over the circle. circle.buttonMode = true; // Make sure the circle is back in its starting position. circle.x = 0; circle.y = 0; } // When the user mouses down on the circle, it will start dragging. private function onMouseDown(e:MouseEvent):void { circle.startDrag(); } // When the user lets go of the circle, it will stop dragging. private function onMouseUp(e:MouseEvent):void { circle.stopDrag(); } // Captivate wants the interactivity off. override public function disableAnswers():void { circle.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDown); circle.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp); // Stop the hand cursor appearing. circle.buttonMode = false; } } } |
Notice how:
- enterRuntime() set up the circle but did not start the interactivity.
- enableAnswers() added two event listeners.
- disableAnswers() removed the same two event listeners. Cancelling out enableAnswers().
- enableAnswers() also made sure the circle was at its starting point in the top left corner. This is because enableAnswers() is called when the user retakes the question. If those two lines of code weren’t there, then the circle would be lying where the audience put it the first time they answered the question. So enableAnswers() not only has to add the interactivity, it also has to reset the question.
Take a look at what the widget does below. Notice when you can drag the circle and when you can’t. You’ll see that between enableAnswers() and disableAnswers() all circumstances are taken care of.
So the widget is enabling and disabling correctly. You may have noticed though, if you click the clear button the question doesn’t reset.
In the next post we’ll look at how to react when the audience clears the question.




