Updating NSProgressIndicator without repeat loop

I’m new to AppleScriptObjC, but not so much AppleScript. In the past, I have had to figure out creative work-arounds for AppleScript being only able to do one task at a time… Unfortunately, I am not having much luck doing this in AppleScriptObjC. What I would like to do seems fairly simple (those are always the hardest, right?)

Here’s what currently happens:

¢ User clicks a button which runs a script on a remote machine
¢ A progress bar for the user appears and continually updates in the UI of my app (repeat loop for 5 mins)
¢ User cannot do anything else in my app until the repeat loop completes

Here’s what I want to happen:

¢ User clicks a button which runs a script on a remote machine
¢ A progress bar for the user appears and continually updates in the UI of my app (repeat loop for 5 mins)
¢ Progress bar runs on a timer, self-updating
¢ User is free to do other things in the app (click more buttons, run other scripts) while the progress bar is updating

Any help, or a nudge in the right direction would be appreciated very much!! Thank you!


  script AppDelegate

          property parent : class "NSObject"
          property progressBar : missing value
          
          on buttonClickedTIMER_(sender)
 
	tell application "Finder" of machine "eppc://username:password@server.local"
		open file "Macintosh HD:Path:To:Application.app"
	end tell

	repeat 300 times                            -----    I want this part
		progressBar's incrementBy_(1)          -----    to be executed
		delay 1                                         -----    without "pausing" the app
	end repeat                                   -----     Is it possible?
	
	progressBar's stopAnimation_(me)     ----- This bit too :)

 end buttonClickedTIMER_

on applicationWillFinishLaunching_(aNotification)
	-- Do Nothing
end applicationWillFinishLaunching_
    
on applicationShouldTerminate_(sender)
	return current application's NSTerminateNow
end applicationShouldTerminate_

end script


You can go close by using an NSTimer to update progress bar. But there is a limit, in that there is only one instance of AppleScript for your application, and it can only do one thing at a time. The key is to try to break your actions into smaller actions, or have them periodically check the event queue, so that the timer gets to do its thing.

NSTimer is what I have been researching, but unfortunately still I don’t understand much about it.

Regardless, this post: http://macscripter.net/viewtopic.php?id=31692 got everything working for me with a bunch of hacked together code.

Thanks for taking the time to respond, Shane Stanley.

Here’s the very basic version of what I needed: Clicking a button from the app’s GUI starts a progress bar that runs for a specified time and then stops… and while the progress bar runs, the app doesn’t freeze (using a repeat loop instead of NSTimer caused the app to “lock up” / freeze while the repeat loop ran). Using NSTimer allowed me to do exactly what I wanted.


script AppDelegate

	property parent : class "NSObject"
	property NSTimer : class "NSTimer"   

	property progressBar : missing value
	property theTimer : missing value
	property x : missing value
 
	on startProgressBarButtonClicked_(sender) -- LINKED TO "START" BUTTON IN IB
	
		set x to 60	

		-- UNHIDE THE PROGRESS BAR:
		progressBar's setHidden_(0)	

		-- CALLS METHOD "startProgressBar_" & STARTS NSTIMER:
		set theTimer to current application's  NSTimer's scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(1, me, "startProgressBar:", "", true)

	end startProgressBarButtonClicked_


	on startProgressBar_(sender)
             
		-- CONTINUALLY UPDATES PROGRESS BAR:
		progressBar's incrementBy_(1)

		set x to x-1

		if x is 0 then
			
			-- STOP THE NSTIMER, STOP THE PROGRESS BAR ANIMATION, AND HIDE THE PROGRESS BAR:
			theTimer's invalidate()
			progressBar's stopAnimation_(me)
			progressBar's setHidden_(1)

		end if

	end startProgress_

end script

FYI, you could also get rid of that property x by using doubleValue() to get the value of the progress bar.

ps - the more you use progress bars - you will find that they work best with some or other loop

I find that working in percentages is easier-you get consistent results and you can easily reuse your code.

i.e.

((currentValue / maxValue) * 100)

set doubleValue to the result

this will obviously only work if you set the maximum value of the progress bar to 100

Good luck