Go Back   The macosxhints Forums > OS X Help Requests > AppleScript



Reply
 
Thread Tools Rate Thread Display Modes
Old 12-31-2012, 07:25 PM   #1
robleach
Prospect
 
Join Date: Feb 2003
Posts: 31
Need Help with a Progress Bar

Hi,

I have an applescript which queries a website to annotate songs in my iTunes library. It works fine (with an occasional error I'm separately trying to track down) but I decided to try xcode for the first time to add a progress bar indicator to let me know how much longer it has to go. I was loosely following a procedure found here. The article is outdated, but it gave me an idea of what to look for.

I can get the xcode project to run and annotate the songs, but only if I leave the progress window defunct. As soon as I try to uncomment the code which tries to initialize and update the progress bar, it won't compile. Here's the code - edited for brevity. I'll also paste the app interface below (generated by a script I found).

Code:
script Comment_3AppDelegate
	property parent : class "NSObject"
	property separator : ";"
	
	
	on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened
		try
			activate
			set numtracks to 0
			set sel to {}
			tell application "iTunes"
				
				-- copy (a reference to (get view of front window)) to thePlaylist
				set thePlaylist to view of front browser window
				if selection is not {} then
					set sel to a reference to selection
				else -- its the whole playlist
					if thePlaylist is not library playlist 1 then
						set sel to a reference to every track of thePlaylist
					else
						display dialog "Select some tracks" buttons {"Cancel"} default button 1 with icon 2 giving up after 15
					end if
				end if
				
				set appendum to (display dialog "Search to Comment, Version 3

Append search result before or after existing comments?" buttons {"Cancel", "Before", "After"} default button 2 with icon 1 giving up after 60)
				
			end tell
			set tracknum to 0
			set numtracks to number of items of sel
			activate
			open window "Comment 3"

			--This is the section that will not compile - as you can see I've tried different things.  I've commented them out here...

			--set maximum value of progress indicator 1 of window "Comment 3" of application process "Comment 3" of application "System Events" to numtracks
			--tell progress indicator "Progress Bar" of window "Comment 3"
			--set visible to true
			--	set uses threaded animation to true
			--	set indeterminate to false
			--	set maximum value to numtracks
			--	start
			--end tell
			--set indeterminate of progress indicator "Progress Bar" of window "Comment 3" to false
			
			tell application "iTunes"
				repeat with this_track in sel
					try
						set theTitle to this_track's name as text
						set theArtist to this_track's artist as text
					on error
						error "Could not set either track name or artist of track " & tracknum & " as text: [" & name of this_track & ", " & artist of this_track & "]"
					end try
					set tracknum to tracknum + 1
					
					--set contents of text field "ProgressText" of window "ProgressWindow" to "Processing track " & tracknum & " of " & numtracks & ": " & theTitle & " by " & theArtist
					
					--set content of progress indicator "ProgressBar" of window "ProgressWindow" to tracknum
					--update window "ProgressWindow"
										
					set command to "~/Library/iTunes/Scripts/search.pl -n \"" & theTitle & "\" -a \"" & theArtist & "\""
					
					try
						set theresult to do shell script command
					on error
						error "Command failed: [" & command & "]"
					end try
					
					try
						set theLastCharPos to length of (get this_track's comment)
					on error
						error "Could not get length of current track's comment"
						set theLastCharPos to 0
					end try
					
					try
						if theLastCharPos is greater than 0 then
							if button returned of appendum is "Before" then
								set this_track's comment to (theresult & separator & (get this_track's comment))
							else
								set this_track's comment to ((get this_track's comment) & separator & theresult)
							end if
						else
							set this_track's comment to theresult
						end if
					on error
						error "Could not annotate the current track"
					end try
					
				end repeat
			end tell
			
			quit
			
		on error theErrorMessage number theErrorNumber
			if theErrorNumber = -128 then quit
			error theErrorMessage number theErrorNumber
		end try
		
	end applicationWillFinishLaunching_
	
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return current application's NSTerminateNow
	end applicationShouldTerminate_
	
end script
And here's the app interface (the relevant part anyway):


Code:
window "ASCAP to Comment 3" of application process "ASCAP to Comment 3" of application "System Events"
	button 1
	button 2
	button 3
	progress indicator 1
	text field 1
	static text "ASCAP to Comment 3"
-----
menu bar 1 of application process "ASCAP to Comment 3" of application "System Events"
	menu bar item "Apple"
		menu "Apple"
...
I suspect that I did something wrong, or not enough in the "Interface Builder" application. There is a step in the procedure I was following where you are supposed to select an event handler and set it to applescript, but I could not find that in my version of interface builder.

The errors I get for various lines are along the lines of:

Code:
Comment_3AppDelegate.applescript:49: error: A identifier can’t go after this identifier. (-2740)
Command /usr/bin/osacompile failed with exit code 1
which refer for example, to this line:


Code:
set maximum value of progress indicator 1 of window "Comment 3" of application process "Comment 3" of application "System Events" to numtracks
Any ideas? I've tried accessibility inspector and the paths of the relevant objects should all be good.

Thanks,
Rob
robleach is offline   Reply With Quote
Old 12-31-2012, 10:46 PM   #2
Red_Menace
All Star
 
Join Date: Mar 2006
Location: Littleton, Colorado, USA
Posts: 506
You are using AppleScript Studio terminology (which was deprecated in Snow Leopard) in an AppleScriptObjC project. One of the main differences when using ASOC is that the various UI objects are referenced by properties and not by the name and hierarchy (that `progress indicator "Progress Bar" of window "Comment 3"` stuff).

Typically you would add some instance properties to your project for the UI objects you want to deal with, and then from the Interface Editor connect the UI objects to their respective properties (properties set to 'missing value' will show up in the Editor):

Code:
	property myProgressBar : missing value -- connected to the progress bar
	property myTextField : missing value -- connected to the text field
Once everything is connected up, you can then use the various methods from NSProgressIndicator and NSTextField (and their parents) - for example, you can set up your progress bar by doing something like:

Code:
	tell myProgressBar
		setMaxValue_(numtracks)
		setUsesThreadedAnimation_(true)
		setIndeterminate_(false)
	end tell
... and update by doing something like:

Code:
	myTextField's setStringValue_("Processing track " & tracknum & " of " & numtracks & ": " & theTitle & " by " & theArtist)
					
	tell myProgressBar
		incrementBy_(1)
		display()
	end tell
You should also avoid cramming everything into the applicationWillFinishLaunching_ handler, since it is called before the application object is initialized. A better spot to kick everything off is the applicationDidFinishLaunching_ handler, which is called after the application has been launched and initialized but before it has received its first event.
__________________
MacBook Pro / OS X Mountain Lion (10.8.3) / Xcode 4.6 / [various (much) older stuff keeping dust off the shelves]
Red_Menace is offline   Reply With Quote
Old 01-01-2013, 01:28 PM   #3
robleach
Prospect
 
Join Date: Feb 2003
Posts: 31
Progress on progress bar

Wow, thanks Red Menace. Thanks to you, I've made quite a bit of progress on my progress bar. I created the properties and connected them in the Interface builder. Feeling ambitious during the effort, I also added a stop button (which actually works!). Here's where I'm stuck however... With the code inserted as-is, as you suggested (except I added a "start" command - otherwise the window doesn't show up (alternatively I tried setting the visibility and simply opening the window to the same effect)), what happens is the progress window appears but the script does not progress from there. The progress bar does not fill and the annotations don't get added to my tracks. If I simply comment out the start command, the progress window does not appear and the tracks get annotated.

I added dialog windows for debugging. The one right before the progress window setup appears, but the others do not show up unless I comment out the "start" command (which causes the progress window to now appear). I also tried "start_()".

Anyone know where to go from here? Here's the new code:

Code:
script Comment_3AppDelegate
	property parent : class "NSObject"
	property separator : ";"
	property myProgressBar : missing value
	property myProgressText : missing value
	
	on buttonClicked_(sender)
		quit
	end buttonClicked_
	
	on applicationDidFinishLaunching_(aNotification)
		try
			activate
			set numtracks to 0
			set sel to {}
			tell application "iTunes"
				
				-- copy (a reference to (get view of front window)) to thePlaylist
				set thePlaylist to view of front browser window
				if selection is not {} then
					set sel to a reference to selection
				else -- its the whole playlist
					if thePlaylist is not library playlist 1 then
						set sel to a reference to every track of thePlaylist
					else
						display dialog "Select some tracks." buttons {"Cancel"} default button 1 with icon 2 giving up after 15
					end if
				end if
				
				set appendum to (display dialog "Search to Comment, Version 3

Append search result before or after existing comments?" buttons {"Cancel", "Before", "After"} default button 2 with icon 1 giving up after 60)
				
				set tracknum to 0
				set numtracks to number of items of sel
				
				display dialog "About to start progress bar" buttons {"Cancel", "OK"} default button 2 with icon 1 giving up after 60
				tell myProgressBar
					setMaxValue_(numtracks)
					setUsesThreadedAnimation_(true)
					setIndeterminate_(false)
					start
				end tell

				display dialog "Progress Bar Started" buttons {"Cancel", "OK"} default button 2 with icon 1 giving up after 60
				
				repeat with this_track in sel
					try
						set theTitle to this_track's name as text
						set theArtist to this_track's artist as text
					on error
						error "Could not set either track name or artist of track " & tracknum & " as text: [" & name of this_track & ", " & artist of this_track & "]"
					end try
					set tracknum to tracknum + 1
					display dialog "Doing a track" buttons {"Cancel", "OK"} default button 2 with icon 1 giving up after 60
					
					myProgressText's setStringValue_("Processing track " & tracknum & " of " & numtracks & ": " & theTitle & " by " & theArtist)
					
					tell myProgressBar
						incrementBy_(1)
						display()
					end tell
					
					set command to "~/Library/iTunes/Scripts/search.pl -n \"" & theTitle & "\" -a \"" & theArtist & "\""
					
					try
						set searchresult to do shell script command
					on error
						error "Command failed: [" & command & "]"
					end try
					
					try
						set theLastCharPos to length of (get this_track's comment)
					on error
						error "Could not get length of current track's comment"
						set theLastCharPos to 0
					end try
					
					try
						if theLastCharPos is greater than 0 then
							if button returned of appendum is "Before" then
								set this_track's comment to (searchresult & separator & (get this_track's comment))
							else
								set this_track's comment to ((get this_track's comment) & separator & searchresult)
							end if
						else
							set this_track's comment to searchresult
						end if
					on error
						error "Could not annotate the current track"
					end try
					
				end repeat
				
			end tell
			
			quit
			
		on error theErrorMessage number theErrorNumber
			if theErrorNumber = -128 then quit
			error theErrorMessage number theErrorNumber
		end try
		
	end applicationDidFinishLaunching_
	
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return current application's NSTerminateNow
	end applicationShouldTerminate_
	
end script
Thanks,
Rob
robleach is offline   Reply With Quote
Old 01-01-2013, 01:58 PM   #4
Red_Menace
All Star
 
Join Date: Mar 2006
Location: Littleton, Colorado, USA
Posts: 506
It sounds like you don't have the progress bar set to display if it is stopped (in the Interface Editor's Attributes Inspector), although when you start incrementing it it should appear. A progress indicator doesn't have a start method, so the error is skipping the rest of the code - you can look at the debug console to see if there are any errors (log statements are also placed in the console).
__________________
MacBook Pro / OS X Mountain Lion (10.8.3) / Xcode 4.6 / [various (much) older stuff keeping dust off the shelves]
Red_Menace is offline   Reply With Quote
Old 01-07-2013, 01:41 PM   #5
robleach
Prospect
 
Join Date: Feb 2003
Posts: 31
Finally got around to playing with this again. The progress bar is set to display as far as I can tell (clicked on the progress bar in Interface Builder and hidden is unchecked). Even though the progress window is set to be "Visible at Launch", it does not appear unless I set the visible to true in the applescript code (or simply open the window via applescript). Oddly, the tracks get annotated unless the window is visible... I looked into console and this is all I get:

Code:
1/7/13 2:22:58.759 PM ASCAP to Comment 3: *** -[Comment_3AppDelegate applicationDidFinishLaunching:]: iTunes got an error: Unknown object type. (error -1731)
This is probably unrelated, but I don't get any errors when I run the plain applescript from the script menu in iTunes, so I imagine it might have to do with my progress bar interface... Though when I run the plain applescript, I noted it was going slow. In fact, the XCode project runs faster with the progress window disabled. I don't know why that is, however I do get a message at about the same time as each annotation is added:

Code:
1/7/13 2:29:52.225 PM com.apple.backupd: Waiting for index to be ready (101)
1/7/13 2:30:52.580 PM com.apple.backupd: Waiting for index to be ready (101)
1/7/13 2:31:52.853 PM com.apple.backupd: Waiting for index to be ready (100)
There should be about a 6 second sleep between each server query, but the delay appears to be about a minute. And as I mentioned, this does not occur in the XCode project (when the progress window is disabled).

Perhaps this little project is simply more than I can chew... I'm going to see if I can find any current tutorials on making progress bars for applescripts.

Rob
robleach is offline   Reply With Quote
Old 01-07-2013, 07:29 PM   #6
Red_Menace
All Star
 
Join Date: Mar 2006
Location: Littleton, Colorado, USA
Posts: 506
One of the big differences when using AppleScript in Xcode is that you need to watch out about blocking the user interface. If your application immediately starts doing stuff and doesn't let the system handle events, for example staying in a repeat loop, the UI will not do what you want it to.

If I make a minimal script that just steps through the iTunes selection, nothing will happen unless I give the system some time to do its thing. The following example works for me - try commenting out the fetchEvents() hander calls to see what I am talking about:

Code:
script AppDelegate
	
	##################################################	
	# MARK: -
	# MARK: Script Properties
	#
	property parent : class "NSObject"
	
	
	##################################################	
	# MARK: -
	# MARK: Interface Editor Outlets
	#
	property myWindow : missing value -- connected to the window
	property myTextField : missing value -- connected to the text field
	property myProgressBar : missing value -- connected to the progress bar
	
	
	##################################################	
	# MARK: -
	# MARK: Interface Editor Actions
	#
	on buttonClicked_(sender)
		log "quitting..."
		tell me to quit
	end buttonClicked_
	
	
	##################################################	
	# MARK: -
	# MARK: Delegate Handlers
	#
	on applicationDidFinishLaunching_(aNotification)
		tell myProgressBar
			setUsesThreadedAnimation_(true)
			setIndeterminate_(false)
		end tell
        delay 4 -- give window time to show up
		doStuff()
	end applicationDidFinishLaunching_
	
	
	on applicationShouldTerminate_(sender)
		return current application's NSTerminateNow
	end applicationShouldTerminate_
	
	
	##################################################	
	# MARK: -
	# MARK: Script Handlers
	#
	on doStuff() -- step through iTunes selection
		tell application "iTunes" to set sel to selection
		set numtracks to (count sel)
		log (numtracks as text) & " items selected"
		
		tell myProgressBar to setMaxValue_(numtracks)
		
		tell application "iTunes" to repeat with this_track from 1 to numtracks
			my fetchEvents()
			
			set theTitle to name of (item this_track of sel)
			set theArtist to artist of (item this_track of sel)
			
			set theText to ("Processing track " & this_track & " of " & numtracks & ": " & theTitle & " by " & theArtist)
			tell me to log theText
			
			tell myTextField
				setStringValue_(theText)
				-- display()
			end tell
			
			tell myProgressBar
				incrementBy_(1)
				-- display()
			end tell
			
			delay 1 -- slow down a bit so you can see the progress
			my fetchEvents()
		end repeat
		
		tell me to quit
		
	end doStuff
	
	
	on fetchEvents() -- handle user events to keep the queue from filling up (Shane Stanley)
		repeat -- forever
			tell current application's NSApp to set theEvent to nextEventMatchingMask_untilDate_inMode_dequeue_(current application's NSAnyEventMask, missing value, current application's NSEventTrackingRunLoopMode, true)
			if theEvent is missing value then -- none left
				exit repeat
			else
				tell current application's NSApp to sendEvent_(theEvent) -- pass it on
			end if
		end repeat
		return
	end fetchEvents
	
	
end script
__________________
MacBook Pro / OS X Mountain Lion (10.8.3) / Xcode 4.6 / [various (much) older stuff keeping dust off the shelves]
Red_Menace is offline   Reply With Quote
Reply

Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump



All times are GMT -5. The time now is 07:42 PM.


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2013, vBulletin Solutions, Inc.
Site design © IDG Consumer & SMB; individuals retain copyright of their postings
but consent to the possible use of their material in other areas of IDG Consumer & SMB.