How do I animate a determinate progress indicator?

Sorry, i missed that bit, it can vary depending on what the user picks, and the number of files in a folder, but it could be as low as 21, to as high as several thousand.

Here’s the script that sets the amount.

Even when only a small number is used, the bar still doesn’t animate.



on SetUp_(sender)
		set TempTallyName to DiskPath's stringValue() as text
		set MainRecipients to MainMailRecipients's objectValues() as list
		set CCRecipients to CCMailRecipients's objectValues() as list
		Messages's setStringValue_("")
		if TempTallyName = "" then
			my Writemessages("Path is missing. ")
			set workFlag to true
		end if
		if not workFlag then
			set the DataYear to ""
			set StartFlag to 0
			set theProgressFlag to 0
			set tempstring to TheBusinessName & return & return
			set DataYear to (theYear's titleOfSelectedItem()) as text
			set TallyName to (TempTallyName & ".Detailed Yearly Tally " & DataYear) as text
			set DataStart to (startingMonth's titleOfSelectedItem()) as text
			set StartFlag to (startingMonth's indexOfSelectedItem()) as integer
			set DataEnd to (endingMonth's titleOfSelectedItem()) as text
			set endFlag to (endingMonth's indexOfSelectedItem()) as integer
			set WholeList to my ReadFile(TallyName)
			set DataClientYear to theYear's titleOfSelectedItem() as integer
			set TallyName2 to (TempTallyName & "Mail Data " & DataClientYear) as text
			tell application "Finder"
				set theFiles to files of folder TallyName2
			end tell
			set theadjustment to (count of WholeList) div 52
			set theFineadjustment to endFlag - StartFlag + 1
			set theClientadjustment to ((count of theFiles) * 10) + 240
			set TheProgressCycle to 0
			set thetotal to 0
			set theEndFlag to ""
			set TheProgressCycleCount to 0
			if HourlyReport's (state) as integer = 1 then
				set thetotal to thetotal + 1
				set TheProgressCycleCount to TheProgressCycleCount + theFineadjustment * 24
				if colorFlag then set TheProgressCycleCount to TheProgressCycleCount + 20
			end if
			if DailyReport's (state) as integer = 1 then
				set thetotal to thetotal + 1
				set TheProgressCycleCount to TheProgressCycleCount + theadjustment
				if colorFlag then set TheProgressCycleCount to TheProgressCycleCount + 20
			end if
			if MonthlyReport's (state) as integer = 1 then
				set thetotal to thetotal + 1
				set TheProgressCycleCount to TheProgressCycleCount + theadjustment
				if colorFlag then set TheProgressCycleCount to TheProgressCycleCount + 20
			end if
			if theClientReport's (state) as integer = 1 or theClientReportAlphabetically's (state) as integer = 1 then
				set thetotal to thetotal + 1
				set TheProgressCycleCount to TheProgressCycleCount + theClientadjustment
			end if
			if DayReport's (state) as integer = 1 then
				set thetotal to thetotal + 1
				set TheProgressCycleCount to TheProgressCycleCount + 24
				if colorFlag then set TheProgressCycleCount to TheProgressCycleCount + 20
			end if
			if WeeklyReport's (state) as integer = 1 then
				set thetotal to thetotal + 1
				set TheProgressCycleCount to TheProgressCycleCount + (24 * 7)
				if colorFlag then set TheProgressCycleCount to TheProgressCycleCount + 20
			end if
			if TheProgressCycleCount ≠ 0 then
				Progress's setDoubleValue_(0)
				Progress's setHidden_(false)
				Progress's setMaxValue_(TheProgressCycleCount)
				if HourlyReport's (state) as integer = 1 then
					set workFlag to true
					set colorFlag to (UseColor's (state) as integer = 1)
					my writeOnlyMessage("Preparing Hourly report. ")
					my GraphIt3()
				end if
				if DailyReport's (state) as integer = 1 then
					set workFlag to true
					set colorFlag to (UseColor's (state) as integer = 1)
					my writeOnlyMessage("Preparing Daily report. ")
					my GraphIt()
				end if
				if MonthlyReport's (state) as integer = 1 then
					set workFlag to true
					set colorFlag to (UseColor's (state) as integer = 1)
					my writeOnlyMessage("Preparing Monthly report. ")
					my GraphIt2()
				end if
				if theClientReport's (state) as integer = 1 or theClientReportAlphabetically's (state) as integer = 1 then
					set workFlag to true
					set colorFlag to false
					my writeOnlyMessage("Preparing Client report. ")
					my ClientReport()
				end if
				if DayReport's (state) as integer = 1 then
					set workFlag to true
					set colorFlag to (UseColor's (state) as integer = 1)
					my writeOnlyMessage("Preparing Single Day report. ")
					my GraphIt4()
				end if
				if WeeklyReport's (state) as integer = 1 then
					set workFlag to true
					set colorFlag to (UseColor's (state) as integer = 1)
					my writeOnlyMessage("Preparing Weeks report. ")
					my GraphIt5()
				end if
				Progress's setDoubleValue_(TheProgressCycleCount)
			end if
			set workFlag to false
			delay 1
			if WrittenFlag = 0 and SendTheMessageFlag then
				set workFlag to false
				set WrittenFlag to 1
				set my isIdle to true -- this re-enables most of the UI elements via bindings
				delay 2
				my Clearmessages()
				set AddOn to "Client summation eMail"
				if theClientReport's (state) as integer = 1 and theClientReportAlphabetically's (state) as integer = 1 then set AddOn to "Clients summation eMails"
				my Writemessages("Please enter a password into the password box, before the " & AddOn & " can be sent. ")
				--my SecurePasswordEntry_()
			else
				set my isIdle to true -- this re-enables most of the UI elements via bindings
				my Writemessages("Finished.")
				Progress's setDoubleValue_(0)
				Progress's setHidden_(true)
			end if
		else
			say "busy working"
		end if
	end SetUp_

I fear you’re still not listening. This handler is called by a button, yes?

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.