Progress Indicator not executing in time

Hi,
I have a question about the use of the Indeterminate Circular Progress Indicator in Xcode AppleScript Applications, which has baffled me for days.

On the Interface Builder:

  • A button
  • An Indeterminate Circular Progress Indicator
  • A label (next to the Progress Indicator)

The application is very simple: a user clicks the begin button - executing the following function:

on beginBtnClick_(sender)
    -- Show User Notification
    inProgressNotice's setHidden:0
    inProgressSpinner's setHidden:0
    inProgressSpinner's startAnimation:me

    -- PERFORM THE FUNCTION'S MAIN TASK

    -- Hide User Notification
    inProgressSpinner's stopAnimation:me
    inProgressSpinner's setHidden:1
    inProgressNotice's setHidden:1
end beginBtnClick_

How it should run:

  1. Upon clicking the button to execute the function, the progress indicator and label (both initially hidden) should become visible and start spinning up.
  2. The main task of this function will be executed (in my case this involves calling functions in another script, nothing too complex - and it works).
  3. When step 2 completes, the (spinning) progress indicator and the label should stop and hide.

I think we agree that is the basic functionality of any such indicator.

How it behaves instead:

  1. Upon clicking the button, the main task of this function executes immediately.
  2. When the function’s main task has completed, it shows the spinning indicator and the label.
  3. It then stops and hides the indicator and label.

Could somebody clarify what is going on here? I read somewhere that AS does not consider the order of statements in the function but that cannot possibly be right as it wouldn’t make sense.

I don’t want to create a dialog box to inform the user every time that something is happening in the background (that may not be visible to them), so a Circular Progress Indicator is perfect for this.
How can I achieve the desired result here?

When you click a button, the resulting event is handled by calling your handler. Your handler does what it does, and the screen is finally updated before the next event is handled.

You have a couple of choices:

  • Break your code into multiple events, using one of the performSelector methods.

  • Add code to check the event queue, which results in screen updates. You can usually do this with code like this:

    on tickleQueue()
        current application's NSApp's nextEventMatchingMask:0 untilDate:(missing value) inMode:(current application's NSEventTrackingRunLoopMode) dequeue:false
    end fordEvent

Just call it whenever you want the screen to update.

Using your tickleQueue() method, the app now shows the two components. But the strange thing is that the spinning action is not continuous as the program performs its actions. I suspect this has something to do with it executing code in other functions, thus stopping the spinning until data is returned (or something similar).

Currently, I click the button, components show, spinner spins but freezes until function end. How would I tell the progress indicator to keep spinning while the actions happen?

You need to liberally sprinkle calls to that method throughout your code.

Actually, you should probably use this handler instead:

	on fordEvent()
		set theApp to current application's NSApp
		set theMode to current application's NSEventTrackingRunLoopMode
		set theMask to current application's NSAnyEventMask
		repeat
			set theEvent to (theApp's nextEventMatchingMask:theMask untilDate:(missing value) inMode:theMode dequeue:true)
			if theEvent is missing value then exit repeat
			theApp's sendEvent:theEvent
		end repeat
	end fordEvent