A Progress Bar Widget
In the previous section, we created a 'Preloader' script to (1) preload a URL; (2) send a message when the preload is complete; and (3) send 'status' messages while the preload is happening. In this section, we are going to create a progress bar that shows the current status (such as the percentage of the preload that has been completed).
Example Movie can be downloaded here. It contains the scripts discussed in this tutorial.
(Updated 25th June 05)
There are many ways to create progress bars. We can use Flash sprites, simple shapes that are stretched and resized, simple text sprites, widgets provided by Xtras such as OS Controls, and so on. In this example, we are going to use imaging lingo. No matter which way we do it, the script needs to have the ability to respond to two messages that we are going to send to it: (a) a #mShowWorking message, which we will send while we are waiting to connect to a server, and a #ShowProgress(amount) message which we will send when we know how far we have progressed through the preload.
The script below will create an object that will draw a simple 'barberpole' type animation to an image when we send it the #ShowWorking message. When we send the #ShowProgress message, it will replace this barberpole with a simple progress bar.
-- [PARENT SCRIPT] "ProgressBar" (v.1). -- Author defined properties property myColour, myColour2 -- Internally defined properties property myCanvas, myRectOnCanvas, myBuffer, myBufferRect, myAlpha property myStep, mySegmentSize on Initialise (me, aCanvas, aRectOnCanvas, settings) -- stash a reference to the output canvas and rect myCanvas = aCanvas myRectOnCanvas = aRectOnCanvas -- some basic settings myColour = rgb(68,68,68) -- bar colour myColour2 = rgb(255,255,255) -- stripe colour -- create an image buffer myBuffer = image(myRectOnCanvas.width, myRectOnCanvas.height, 16) myBuffer.copyPixels(myCanvas, myBuffer.Rect, myRectOnCanvas) -- store this rect for use later myBufferRect = myBuffer.rect -- set up parameters for working animation myStep = 0 mySegmentSize = myBuffer.height -4 return me end on Destroy (me) -- store the canvas to its previous state myCanvas.copyPixels(myBuffer, myRectOnCanvas, myBufferRect) end on ShowProgress (me, amt) -- make sure the amt is between 0 and 1.0 amt = min(1.0, max(0, amt)) -- create a duplicate of the buffer buffer = myBuffer.duplicate() -- draw a border buffer.draw(myBufferRect, [#ShapeType: #rect, #Color: myColour]) -- calculate a fill rect based on the amount to show progressBarRect = rect(2,2, (myBufferRect.width-2)*amt, myBufferRect.height-2) -- fill the progress bar rect buffer.fill(progressBarRect, myColour2) -- copy the result to the stage myCanvas.copyPixels(buffer, myRectOnCanvas, myBufferRect) end on ShowWorking (me) -- create a duplicate of the buffer buffer = myBuffer.duplicate() -- draw a border buffer.draw(myBufferRect, [#ShapeType: #rect, #Color: myColour]) -- add 1 to the myStep property. This is used to move the 'stripes' along myStep = myStep + 1 -- if the step is bigger than the striped segment, then reset it if myStep > 0 then myStep = -mySegmentSize -- create the temporary inner image for the barber pole innerRect = buffer.rect.inflate(-2,-2) innerImage = image(innerRect.width, innerRect.height, 24) innerImage.fill(innerImage.rect, myColour) -- now draw the stripes L = myStep repeat while true dRect = rect(L, 0, L + mySegmentSize, mySegmentSize+2) innerImage.draw(point(L,0), point( L + mySegmentSize, mySegmentSize),\ [#ShapeType: #Line, #lineSize: 1, #Color: myColour2, #ink: 2]) L = L + mySegmentSize if L > buffer.width then exit repeat end repeat -- add the striped pole to the buffer buffer.copyPixels(innerImage, innerRect, innerImage.rect) -- copy the result to the stage myCanvas.copyPixels(buffer, myRectOnCanvas, myBufferRect) end
This script is designed to do nothing except in response to either #ShowWorking or #ShowProgress messages. To see how it works, have a look at this "PreloaderInterface" frame script that both creates a Progressbar and a Preloader object discussed in the previous section, and then sends messages to the Progressbar:
[FRAME SCRIPT / BEHAVIOUR] property myURL, myProgressBarObj on beginSprite (me) if the runMode = "Author" then clearcache() PreloaderDaemon = script("NetOp.Preloader").new(myURL) PreloaderDaemon.AddListener(me) myProgressBarObj = script("ProgressBar") canvas = (the stage).image rectOnCanvas = rect(10,10,110,22) myProgressBarObj.Initialise(canvas, rectOnCanvas) end on endSprite(me) myProgressBarObj.Destroy() end on exitframe (me) go to the frame end -- Messages Sent by the preloader on PreloadStatusUpdate (me, newOp, statusList) -- member("StatusDisplay").text = statusList.state put statusList.state if statusList.state = "InProgress" then myProgressBarObj.ShowProgress(statusList.fractionDone) else myProgressBarObj.ShowWorking() end on PreloadFinished (me, newOp, errorNum) if errorNum <> 0 then -- get a description of the error description = newOp.GetErrorDescription(errorNum) alert "Network Error!" & return & description else alert "All Done" end -- Author Settings on getPropertyDescriptionList (me) pdList = [:] pdList[#myURL] = [#Comment: "URL", #format: #String, \ #Default: "http://www.lingoworkshop.com/Tutorials/Preloader/Main.dcr"] return pdList end
So whats happening here?
1. When this "PreloaderInterface" behaviour is instantiated and receives the #beginSprite event, it creates a new Preloader object and a ProgressBar object. It keeps a reference to the ProgressBar object so that it can send messages to the ProgressBar.
2. As the preload proceeds, the Preloader Object starts sending #PreloadStatusUpdate messages to the "PreloaderInterface" object. The "PreloaderInterface" object then sends #ShowWorking and #ShowProgress messages to the ProgressBar object (depending on whether the preload has actually started or not).
Example Movie can be downloaded here. It contains the scripts discussed in the tutorial.
(Updated 25th June 05)