Why won't my progress bar show?

I’ve got a script that uses Applescript’s built-in progress bar.

If I save the script as an app, run it, progress-bar UI works fine.

But this script is a bit different… it needs to run called from another script, which is on a command key in FastScripts.

The reason it’s run by another script is that the main script accepts an argument that tells it what command key it was run from… it’s a long script that does slightly different things based on which key invoked it.

So it’s called from a script that’s just:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions

tell script "Script Additions" to set scriptsPath to POSIX path of get_scripts_folder()
set openOrderScript to (POSIX file (scriptsPath & "Bigger Script.app")) as alias
run script openOrderScript with parameters {1}

The function “get_scripts_folder()” just returns the path the scripts are in.

Then the longer script runs.

When I first tried this, I just changed the longer script that gets called - “Bigger Script.app” here - to a .app, where it has been a .scpt. That didn’t make it display the dialog, so I thought “shoot, it won’t work because it’s still being called by a .scpt.”

So I made the calling script a .app. No luck, still no UI.

If I disable the “on run” handler in the big script and set the incoming argument directly, and run that off FastScripts, the progress dialog UI shows fine. So it’s not just a run-of-the-mill script bug in the big script, it’s either something about the “on run” handler, or, more likely I figure, the fact it’s being called from another script, even though both are .apps.

Any help please?

Thanks in advance,

t.spoon

Maybe this is similar to your problem…
https://discussions.apple.com/thread/7185396

Thanks, but I don’t think that thread applies to my situation. I’m not having trouble with delays in showing updates in the progress dialog, I am getting no visible progress dialog at all. The task completes successfully without ever showing the dialog.

It’s like when you run an Apple progress bar from Script Debugger, or script Editor, or save it as a .scpt and run it from Fastscripts - you don’t get the UI. To get the UI, you have to save it as an .app and run the app.

But for some reason, if I save it as a .app, and run that .app from another .app then the dialog is not shown.

I’m hoping some veteran who’s deep in the weeds about how this all works might know some trick here. Like

tell me to activate

or that sort of thing, but I’ve tried that and it didn’t help.

Thanks though,

t.spoon

Maybe I totally wrong to think…

The script that has the progress bar run in main thread ??
and the first script run as background thread.

Shane properly know more…

I know before I just referenced this “bigger script” without providing code, because it’s a big mess of code.

So let me distill it down here to what doesn’t work, which is what I should have posted to begin with.

I save this script in my downloads folder as a .app named “Script 2.app”

set theSteps to 10
set progress total steps to theSteps
set progress completed steps to 0
set progress description to "Doing Something..."
set progress additional description to "Preparing to do other things."
repeat with i from 1 to theSteps
	set progress additional description to "Processing item " & i & " of " & theSteps
	set progress completed steps to i
	delay 1
end repeat
set progress total steps to 0
set progress completed steps to 0
set progress description to ""
set progress additional description to ""

Then I also save this script in my downloads folder as a .app named “Script 1.app”

run script ((path to downloads folder as text) & "Script 2.app") as alias

If I double-click to run Script 2.app, the progress dialog shows and works as expected.
If I double-click to run Script 1.app, the script just launches and runs for 10 seconds then exits, without ever showing the dialog at all.

I’d look at switching to Stephen’s SKProgressBar, but this script will be deployed widely on different OS versions, and it appears from what I’ve seen in discussion here that:

  • There’s no one version of SKProgressBar that’s compatible with both the newest and oldest OS versions I need to deploy to
  • SKProgressBar does not like having multiple versions installed simultaneously

Which would make deploying/using it a PITA.

I can just give up and use notifications. Or we already have Shane’s Dialog Toolkit deployed to all users, and although progress dialogs are not an intended use case there, I could probably hack something together to use it instead.

Or I could always make entirely different versions of the script to run off the different command keys, and deal with the fact that the different versions are 99% shared code by putting it all in a shared library.

But I was hoping maybe someone would just have a simple bit of code that fixes my problem.

I think I find a solution of your example.

Lets break it down.

You like to use script 1 to start script 2

My process:
I save your progress bar script ‘Script2.app’ on Desktop

then I test in Terminal…

So I guess you only need to make do shell script and use the open command

This could be run from a Script Menu. Use chmod +x Scriptname to make executable.

Well, you do in both those editors – just in a different form. FastScripts doesn’t, but it theoretically could.

But I don’t think its ever going to work via run script. Regardless of the format you save in, run script does the same thing – it loads the code as a script object, and runs it. Those properties only work at the top level of a script, which is where the host looks for them.

For some gory details, see: http://blog.latenightsw.com/?p=836

Try in the Script Editor this script. It calls your other script applet:


set theAppAlias to ((path to downloads folder as text) & "Script 2.app") as alias

tell application "Finder"
	activate
	open theAppAlias
end tell

tell application "Script 2" to quit

I think, instead of opening with parameters, you can get/set properties of applet before opening it with Finder.

Ok, thanks everyone, I think I have a better understanding now.

Per Shane, what I’m doing isn’t going to work. So I need a different route.

Fredrik71 and KniazidisR present the workaround of just invoking the script by launching it as an app, just like any application, which does make the dialog show.

The issue there is that the only reason I’m running it from another script at all is that I pass in information that changes its behavior, and I’m not currently seeing how to do that with these methods.

KniazidisR, you say: “I think, instead of opening with parameters, you can get/set properties of applet before opening it with Finder.”

I’m not familiar with that, can you elaborate? On setting the properties before opening it?

I didn’t know that could be done and I’m interested in how that works. However, while I’d like to learn, I doubt it will work in my unusual environment. The script lives on a Dropbox folder shared with about 4 dozen people or so running it constantly. Calling it with an argument, those users can all get different behaviors based on the command key it was run from, even if 10 people are running it at once. But if I’m actually changing a property value in the script externally and then running it, I’m guessing that multiple users hammering the script simultaneously is going to lead to unexpected behavior in some cases. If it’s even possible in this setup - the Dropbox folder with the script is read-only to most users, so they probably can’t modify the properties.

Still, I’m curious to learn how this would work.

So, at this point it seems best to stop calling the same script via different scripts from different command keys and passing in the information about which script called it, and just rewrite the thing to put the very large amount of shared code into a library, split it into different scripts, which run directly off the command keys.

Thanks everyone,

t.spoon.

The first Script could ask for input (string) (AppleScript)
(execute bash script with params)

Inside the bash script you use if statement to open the Script 2 with your input.

I did something like this when I did Automation in command-line for Keynote.

Bash scripting is very powerful when it comes to execute things with specific input params.

If you are interesting I could maybe do some example.

Thanks Fredrik71, I am interested in ways to call an Applescript and pass information into it other than using “run script [some script] with parameters {x}”

Sorry if my explanation of this is very messy. The reason I do it like this is because I
use command-line to automate scripting in Keynote. I like to have different options
and different AppleScripts to do specific things with input. But make it simple
to make bash script to run.

The run handler take arguments and you could decide how many you like.
You maybe need to change the index of items in this example I start with 2 of makeObjectText
The repeat loop will build a list of arguments.

The handler could have if else statement to execute different things.

We could use bash shell script to execute a specific script with params_string (parent_script1)
if we save the bash script to runme.sh (do chmod +x runme.sh)

we could do…
runme.sh parent_script1 my_args_for_applescript

on run argv
	
	set aList to {}
	
	try
		repeat with i from 1 to (count items of argv)
			if (count items of argv) > 0 then
				copy item i of argv to end of aList
			end if
		end repeat
	end try
	
	--~~~~~~~~~~~~
	
	makeObjectText(get item 2 of aList, get item 3 of aList)
	
end run

on makeObjectText(idx, objText)
	tell application id "com.apple.iWork.KeyNote"
		tell front document to tell current slide
			if idx is "1" then
				set the object text of the default title item to objText
			else if idx is "2" then
				set the object text of the default body item to objText
			else if idx is "3" then
			
				tell shape 1
					set the object text to objText
				end tell
			else if idx is "4" then
				tell shape 2
					set the object text to objText
				end tell
			else if idx is "5" then
				tell shape 3
					set the object text to objText
				end tell
			else if idx is "6" then
				tell shape 4
					set the object text to objText
				end tell
			else if idx is "7" then
				tell shape 5
					set the object text to objText
				end tell
			else
				missing value
			end if
		end tell
	end tell
end makeObjectText

Example of my working flow I only need to do this in bash script.

Every line in the bash script execute commands in AppleScript. (the process is very fast)

If I understand correctly, that’s probably right. But…

You can pass launch arguments like this:

use framework "Foundation"
use framework "AppKit"
use scripting additions

set thePath to "~/Desktop/Test App.app"
set thePath to (current application's NSString's stringWithString:thePath)'s stringByExpandingTildeInPath()
set theURL to (current application's NSURL's fileURLWithPath:thePath)
set argDict to current application's NSDictionary's dictionaryWithObject:{"-blahBlah", "Hello world"} forKey:(current application's NSWorkspaceLaunchConfigurationArguments)
set ws to current application's NSWorkspace's sharedWorkspace()
ws's launchApplicationAtURL:theURL options:(current application's NSWorkspaceLaunchDefault) configuration:argDict |error|:(missing value)

And handle them like this:

use framework "Foundation"
use framework "AppKit"
use scripting additions

on run
	set x to (current application's NSUserDefaults's standardUserDefaults()'s objectForKey:"blahBlah")
	if x is not missing value then
		my blahBlah:(x as text)
	end if
end run

on blahBlah:x
	display dialog x
end blahBlah:

Hi, spoon. I was at work.

The Shane already shown you how to change the outer script’s properties. But as I read then above you want the outer script to be read/only for the users. So, here is workaround how to take different behaviour for different users (that is, providing parameters):

Save you Script 2.app as this:


on showProgressBar(userName)
	
	set theSteps to 10
	set progress total steps to theSteps
	set progress completed steps to 0
	set progress description to "Doing Something for " & userName
	set progress additional description to "Preparing to do other things."
	repeat with i from 1 to theSteps
		set progress additional description to "Processing item " & i & " of " & theSteps
		set progress completed steps to i
		delay 1
	end repeat
	set progress total steps to 0
	set progress completed steps to 0
	set progress description to ""
	set progress additional description to ""

end showProgressBar

Run Script 1 as this (providing user name):


set theAppAlias to ((path to downloads folder as text) & "Script 2.app") as alias

set outerScript to load script theAppAlias
set userName to "KniazidisR" -- test with other user names too

return outerScript's showProgressBar(userName)

Actually, this is simpler and probably more useful:

	set theArgs to current application's NSProcessInfo's processInfo()'s arguments() as list

I have done this for other situations not directly ‘applet’

do shell script "open " & my_application & " --args " & my_args

I had a idea of using environment variable to store a string its very common in CGI.
But then I realised I could use clipboard instead to pass the argument.

I test with your script and passing a progress step variable.

Script 1 open from Script Menu

set envString to display dialog "Type the arg ex. 5" default answer ""
set theString to envString's text returned

set the clipboard to theString

do shell script "open ~/Desktop/Script100.app"

Script 2

on run argv
	set theArgs to the clipboard as text
	return my progressBar:theArgs
end run

on progressBar:_argString1
	set theSteps to (_argString1)
	set progress total steps to theSteps
	set progress completed steps to 0
	set progress description to "Doing Something..."
	set progress additional description to "Preparing to do other things."
	repeat with i from 1 to theSteps
		set progress additional description to "Processing item " & i & " of " & theSteps
		set progress completed steps to i
		delay 1
	end repeat
	set progress total steps to 0
	set progress completed steps to 0
	set progress description to ""
	set progress additional description to ""
end progressBar:

This example show that you could send a list of argument to clipboard

set a to {"a", "b", "c"}
set the clipboard to a

set b to the clipboard as list

return {item 1 of b, item 2 of b, item 3 of b}

I find a script on Stack Overflow… to use Apple’s Script Menu’s progressbar menu.

use framework "Foundation"
use scripting additions

on run
	set thePath to POSIX path of (path to desktop) & "runInScript.scpt"
	runInScriptMonitor(thePath)
end run

on runInScriptMonitor(script_path)
	set {script_task, url_error} to current application's NSUserScriptTask's alloc()'s initWithURL:(script_path as POSIX file) |error|:(reference)
	if url_error is not missing value then error (url_error's localizedDescription as string) number (url_error's code as integer)
	script_task's executeWithCompletionHandler:(missing value)
	return
end runInScriptMonitor

Big thanks to all of you, Fredrik71, Shane, and KniazidisR. All your suggestions are useful and helped me learn.

I’d already gone the simple route - I stopped having the command keys run a script that called another script with different arguments, and just made the command keys each directly run a .app script that included the progress dialog code, with the shared code in a new library.

That’s usually how I’d go about things, it’s just that this script looks like:

[do a bunch of things, set a bunch of variables, all the same regardless of the calling command key]
[do one tiny thing different based on the calling command key]
[do a bunch more stuff using a bunch of the variables set earlier, that’s all the same regardless of the calling command key]

With that sort of structure, just having it be one script where the small differences in behavior were invoked by the different arguments being passed based on the command key made sense.

It looks to me like all your workarounds would work, but by the time I got there, I’d already gone ahead and forgot about a calling script / argument passing, and just made it two separate .apps, each called directly, sharing code via a library. Which finally made the UI show.

I’m sure Shane probably understands, but I don’t understand why something like “Display dialog” works perfectly fine in almost every situation, but displaying progress hides anytime you do anything in the most slightly different way.

Look in the Variables list in Script Debugger, where it shows AppleScript. Expand it to show AppleScript’s properties, and you’ll see that progress description et al are just properties, much the same as text item delimiters.

Save this script on your desktop as Delims.scpt:

set text item delimiters to {"blah blah blah"}

Now tell me what you expect when you run this script:

set deskPath to path to desktop as text
set theScript to (deskPath & "Delims.scpt") as alias
run script theScript
return {"one", "two"} as text