How do I animate a determinate progress indicator?

No, it’s called by your handler; the button does not stay blue any more.



on processInfoAfterDelay_(sender) -- parameter is unused but one is required, as is the underscore
		set my isIdle to false -- this effectively disables most of the UI elements via bindings
		performSelector_withObject_afterDelay_("SetUp:", sender, 0.0) -- this is our *one* Cocoa command; it calls our handler with a small delay so the UI doesn't block, otherwise the button would stay highlighted and nothing else would change in the dialog until the job is finished
	end processInfoAfterDelay_
	
	-- ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢ Daily Report ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢
	on SetUp_(sender)
	

This is weird, I tried out this:

on subgo_(sender)
	set valtimes to (valwinnum's stringValue()) as integer
	repeat with valrep from 1 to valtimes
		set valbar to ((100 / valtimes) * valrep) as number
		valwindbar's setDoubleValue_(valbar)
		delay 1
	end repeat
end subgo_

But it isn’t smooth, it is supposed to be sudden? I swear others on my Mac aren’t, or do they have a huge number of progressions?

In that case I’m lost, and I really can’t tell just form looking at so much code. What I do know is that setting properties that relate only to indeterminate bars will not help.

Try a simpler project. Does my sample do what you expect to happen, for example?

Yes, your project animates fine, but is jerky.

I’ll try playing with it to see if i can stuff it up like my project.

Regards

Santa

I think this is the problem: you’re expecting some kind of smoothness that just isn’t available short of setting a very high maximum value and incrementing all the time. When you set the value, that’s what it becomes – it doesn’t slowly crawl from the present value to your new value.

I tried smoothness wit this:

on subgo_(sender)
	set valtimes to (valwinnum's stringValue()) as integer
	repeat with valrep from 1 to valtimes
		set valbar to ((100000 / valtimes) * valrep) as number
		valwindbar's setDoubleValue_(valbar)
		delay 0.001
		log 1
	end repeat
end subgo_

It’s the same without the log, if I input 1000 it takes alot more than a second. As well as 100000 this has been tried with maximums of 1, 100, 1000, always takes ages. Inputting 100 takes about 5 seconds on any max.

But I’m not setting a value, only the total length.

Your script is bound to a value that it jumps to, mines not. Mine uses the incrementBy_(number) method. Perhaps that’s the problem, but i’m not sure how to convert to your method.

You’d expect the increment method to still animate though, surely

Regards

Santa

I’ve tried them, they both jump, it really doesn’t matter, you need to break it up for smoothness.

They’re effectively the same thing.

The animation is the moving diamond pattern; the change of length should be more-or-less instant. If you want it to move in tiny increments so it looks smooth, you need to set its length in tiny increments (and probably keep using displayIfNeeded()). And if you’re doing anything lengthy in AppleScript, you probably won’t be able to update it often enough to look perfectly smooth anyway.

G’day Richard

I’ve tried both ways too, and without displayIfNeeded() they ARE jerky.

But still no animation, even with the following code.



on UpDateProgress(incP)
		repeat incP times
			set TheProgress to TheProgress + 1
			Progress's setDoubleValue_(TheProgress)
			--Progress's incrementBy_(1)
			Progress's displayIfNeeded()
			--Progress's setUsesThreadedAnimation_(true)
		end repeat
	end UpDateProgress

G’day again.

I’ve cracked it.

Smooooooth, animated progress.



on UpDateProgress(incP)
		repeat incP times
			set TheProgress to TheProgress + 1
			Progress's animate_(true)
			Progress's setDoubleValue_(TheProgress)
			Progress's displayIfNeeded()
		end repeat
	end UpDateProgress

Not sure how the displayIfNeeded or animate help, I’m doing fine without.

Darned if I know why Richard, but I’ve got it working, and that’s the main thing. Perhaps it’s because I’ve called the updating as a sub-routine, who knows.

BTW, I’ll still shout you a beer or two Shane, if your ever up this way, thanks for the help.

Regards

Santa

Humor me: remove the animate_ and see if it makes any difference.

Oh and then the displayIfNeeded :lol:

Doesn’t animate Shane, AND it only animates when the routine gets called. If there’s any delay, the animation stops, so it’s not foolproof. But, it’s better than no animation at all.

Richard, the same, all three commands have to be there.

Regards

Santa

I’ve tried a simple project with a scroll bar and button, and the behaviour is exactly the same. All three commands must be used if setting the scroll bar programatically.

The scroll bar is called ‘progress’, and the button is bound to ‘processInfoAfterDelay’ if anyone want to play with it.

It’s a pain in the proverbial that there doesn’t seem to be a command that set the animation going and keeps it going.

Regards

Santa


script Scroll_testAppDelegate
	property parent : class "NSObject"
	property Progress : missing value
	property isIdle : true
	
	on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened 
	end applicationWillFinishLaunching_
	
	on processInfoAfterDelay_(sender) -- parameter is unused but one is required, as is the underscore
		set my isIdle to false -- this effectively disables most of the UI elements via bindings
		performSelector_withObject_afterDelay_("SetUp", sender, 0.0) -- this is our *one* Cocoa command; it calls our handler with a small delay so the UI doesn't block, otherwise the button would stay highlighted and nothing else would change in the dialog until the job is finished
	end processInfoAfterDelay_
	
	on SetUp()
		Progress's setDoubleValue_(0)
		Progress's setHidden_(false)
		Progress's setMaxValue_(2000)
		repeat 200 times
			my UpDateProgress(10)
		end repeat
	end SetUp
	
	on UpDateProgress(incP)
		repeat incP times
			Progress's incrementBy_(1)
			Progress's displayIfNeeded()
			Progress's animate_(true)
		end repeat
	end UpDateProgress
	
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return true
	end applicationShouldTerminate_
	
end script

Interesting. The trouble there, I think, is that your script is artificial in that it’s doing nothing else, so it’s sending the commands so fast it’s overwhelming things. What your extra commands are actually doing is slowing things down.

Change your script like this and see what a slight delay does:

	on SetUp()
		Progress's setDoubleValue_(0)
		Progress's setHidden_(false)
		Progress's setMaxValue_(2000)
		repeat 2000 times
			my UpDateProgress(1)
			delay 1.0E-3
		end repeat
	end SetUp
	
	on UpDateProgress(incP)
		repeat incP times
			Progress's incrementBy_(1)
			--Progress's displayIfNeeded()
			-- Progress's animate_(true)
		end repeat
	end UpDateProgress

I suspect that a script doing real work might have the same effect.

Thanks Shane, that made a difference.

I altered my script to bind to a Property value as your example does, and it still did not scroll smoothly unless I put in the displayIfNeeded. It simply jerked from one handler to the next.

Putting the time delay in has made it scroll smoothly, and with animation, without the extra routines.

However the animation stalls in the few places where the script handlers are working without calling for an update. Is this normal? I thought Apples installers kept animating even when the progress was stopped briefly.

Regards

Santa

Yes, it’s normal – apps tend to do things asynchronously or in separate threads when they’re time-consuming, but we don’t have that luxury in AS. You could try setUsesThreadedAnimation_(true), but the documentation suggests this might slow the app down.