Australian Toolbook User Group

Toolbook Tips & Techniques

Previous Page Next Page


The idle message is a fantastic message to intercept when you want to get things done as a background process.

Sometimes though, you may not get an idle message if the focus of the program is somewhere strange, so a peroidic timer should also be considered as a way to trigger code whilst the user of your program is doing something else.



Ways to interrupt processing

Solution by Carl Steinhilber

Question: Is there a script I can put in a button so that a user can get back control, whatever script is being executed. I tried mmClose all, but this works only on multimedia files. What if I have a script going that includes many step loops, etc. I need a script that will always work and interrupt any script I am running.

Answer: Unfortunately, you're looking at this from the wrong way around :) The trick is not "can I interrupt a script with step loops", but, rather, "can I create scripts with steps that can be interrupted". You CAN create a loop such as:

global  logical  exitProcess
exitProcess = FALSE
step i from 1 to 100000
     -- do something
     yieldApp()
     if exitProcess then
         break step
     end
end

then, on your button you wish to let interrupt the process:

to handle buttonClick
     global  logical  exitProcess
     exitProcess = TRUE
end

But this is not good practice. And, particularly in Toolbook, you probably will not love the reliability or response time. The reason is the system is trying to execute the steps as fast as possible... and is doing it's best to ignore other system events (such as mouse clicks, etc). The only way to get it to pay any attention whatsoever to these other things is to execite a yieldApp() method... but, unfortunately, this causes Toolbook to pay attention to ALL the system events that may have been accumulating while the step loop was processing.

It would be better to write the stepping script in such a way that it never lets all these events accumulate to be processed all at once, but rather process them as they come in. One way to accomplish this that I'm fond of using (Ian will probably kick me for this), is to use a timer or the idle handler to handle the looping.

In the handler that initiates the loop process, instead of having a step event, simply set a book property:

      set the doMyProcess of this book to TRUE

Then, create an idle handler:

to handle idle
   if (the doMyProcess of this book) then
          -- do stuff
   end if
end idle

Then, use a script for the interrupt button similar to the one above:

to handle buttonClick
    set the doMyProcess of this book to FALSE
end

Since the idle handler (and timer handlers) will only fire when the system has finished processing other messages, your buttonClick on the interrupt button is recognized much more efficiently and quickly than with the step loop above. And since the system can process event practically at will, the event queue will usually only have a single event in it to process at any one time... so it really doesn't slow things down all that much (though you will notice SOME degradation).

The trick is to think of virtually everything that happens in Windows as an "event". And instead of a buttonClick being sent right to Windows to get processed, it's actually thrown onto a queue or "stack" (much like a Toolbook stack). And even multitasking doesn't negate the fact that the events in this stack must be processed one at a time... and usually in the order that they were put into the stack (first in, first out). So in the example script above that uses the step loop, while that loop is processing Windows is not looking at events in that stack. So it will start to build up like:

     "update system time"
     "move cursor"
     "hilight text"
     "check serial port"
     "beep speaker"
           :

And when you click on the interrupt button, of course that mouse click is thrown in after the last item of the stack. So by the time yieldApp() is called, all the other system events must be processed before the buttonClick is even seen.

But if you use the timer or idle handler, and the system is continually able to process the event stack... Windows will "see" the buttonClick MUCH quicker, and the reaction time will be much more desirable.



Idle handler causing slow response

Solution by Chris J. Carden , Asymetrix

The problem with checking the mmStatus in the idle handler is that, because the idle comes so fast, most of the CPU resources are burnt up just checking. The best way to tell if the clip has ended is to use the "notify" option. If that doesn't work for your situation, put some 'mmYield' commands in the idle handler or add a delay so that you only check once every second or two.



Checking the status of a checkbox periodically

Question: I am using a script in a page to determine if the checked of a button is true or false and to then show a pict based on the status of the checked. The problem is, I am using the idle handler. Any other handler such as buttonclick only gives the result I want if the page is the reciever of the buttonclick. Other objects on the page CAN effect the checked status. I need a script that allows the page to recieve the checked status no matter how the checked status was invoked.

Use forward
Solution by Craig McDonald

You could forward your buttonClick handler, then the page would receive it.

Try a timer
Solution by Clifford Dedmore

Try a timer that checks the status of the button every 1/2 second (much less time intensive than the idle).

Try notifyafter buttonclick
Solution by The Arben Group

Try

   notifyafter buttonClick

I have used this before.



Initiating a slideshow when the user has been idle for 15 seconds

Question
Solution by Aggelos Grondas

With Toolbook can I have 20-30 different clips playing in serial order at idle time? I want after 10-15 secs of idle, the application go to first page and then play 20 clips one by one.

In Human Script:

Hey nobody uses me for 15 seconds
ok go to first page
play video "who"
is video "who" finished?
play video "who2"
end
Reply - use a notify handler
Solution by Clifford Dedmore

Yes you can, but using mmplay with a Notify handler to queue up the next clip. Look at the syntax for the mmPlay command and you will see the Notify parameter.

Followup question - hey I want more clips
Solution by Aggelos Grondas

Question: I was talking about 20-30 different clips.The notifier seems to be work only with one (clip).

Here is the *Open*Script [ I currently have which I want someone to enahnce ]:

to handle EnterPage
 mmOpen clip "test1"
 mmPlay clip "test1" in stage "video" notify self
end
to handle mmNotify cRef, cCommand, cResult
 if cRef = clip "test1" and \
   cResult = "successful" then
  mmPlay clip "test2" in stage "video" \
  notify self
 if cRef = clip "test2" and \
   cResult = "successful" then
     mmPlay clip "test3" in stage "video" \
     notify self
      if cRef = clip "test3" and \
   cResult = "successful" then
     mmPlay clip "test4" in stage "video" \
     notify self
     if cRef = clip "test4" and \
   cResult = "successful" then
     mmPlay clip "test5" in stage "video" \
     notify self
 end if
 end if
 end if
 end if
 end

Any suggestions?

Reply - ok here's some code to do it
Solution by Clifford Dedmore
to handle enterPage
  my counter = 0
  send MMNotify
  forward
end
to handle MMNotify
  increment my counter
  conditions
    when my counter = 1
      mmPlay clip "firstone" in stage "foo" \
      notify self
    when my counter = 2
      mmPlay clip "secondone" in stage "foo" \
      notify self
    when my counter = 3
      ...
      ...
      ...
  end
end

NOTE: This is untested, but should work without much modification.


To access thousands more tips offline - download Toolbook Knowledge Nuggets 

Previous Page Next Page