I am creating an AS Studio application that accesses data in another application (Palm Desktop). It extracts category data to display in a table on startup, so I added a progress window on startup, since it takes a few seconds to get everything from Palm Desktop. Once the data has been gathered and the table window is up, Palm Desktop is still the frontmost application, and it requires the user to click on the table window first, just to bring forward the application so that table data can be selected; 2 clicks when I would like just one. I know that via System Events, frontmost and background are both r/o, so I was wondering if anyone had a nifty method to keep the application up front, even when it is calling another application during it’s execution.
Here is some of the code, if you think it may help:
on will open theObject--This is linked to the main window (startup window)
WriteProgress("main")--This instructs the progress window what to display
set visible of window "progress_window" to true
tell window "progress_window" to center
start progress indicator "progress" of window "progress_window"
set cmd_K to («data utxt2318» as Unicode text)
set contents of text field "instr" of window "main" to ("Select as many categories as you like, using either the Shift or " & cmd_K & " key(s):")
set content of table view 1 of scroll view 1 of window "main" to GetAddrByCat()--This handler calls Palm Desktop to get the initial category data
stop progress indicator "progress" of window "progress_window"
set visible of window "progress_window" to false
end will open
I hope you understand what I am trying to communicate.
Saying “activate” won’t work? As long as it’s not inside any other tell block, it should activate “me”. If a plain activate command won’t work, you could also say ‘tell application “MySuperApp” to activate’.
In your code right before your handler ends, just add “activate” on it’s own line. You should… at any time… be able to simply issue an activate command on your own app to make it frontmost. If you have some code that you are sure gives your frontmost status away, just follow that line with the activate command, and that should do it.
Thanks for the quick reply. Actually, it turns out to be the progress window messing things up, not Palm Desktop. I was pondering things right after my post (a fresh Fuji apple is a great source of objectivity) and I recalled another project I slapped together using Palm Desktop, and the main window was immediately active after the data had been extracted from Palm.
My idea for this project was to have the progress window pop up on startup, just to let the user know that yes, something is happening, please be patient. So, I took the code (posted above) and commented out all lines dealing with the progress window, and it works famously; the startup window (main) appears after a few seconds, and is the active window.
So, I guess I am really asking how to code the appearance of a progress window on startup, and have it leave the main window as the active window when I am finished with it. I tried replacing the last line of the willl open handler (posted above) with close window “progress_window”, but that had the same results as before.
I am sure that I simply am not fully understanding how to effectively use the built in window and/or nib handlers here to do what I want to do, so any input on that would be appreciated.
Ahh, pondering. I’d be a billionaire if I got paid for all the pondering I do.
Anyways, how about…
show window "progress_window"
-- AND --
hide window "progress_window"
Note that the ‘on will open’ handler is fired EVERY time the window opens, not just at startup. If the user can open and close the window at will while the app is running, you may need to either track whether the progress window can open programatically, or use a different handler… like the launched handler… to pop up the progress window only once.
Also note, that if you have the “visible at launch time” box checked for your main window, the window pops up at a weird time (the exact moment it’s unarchived from nib, thus not a safe time to reference objects that are not part of it’s subview hierarchy) and may open before the progress window has been unarchived from the nib. This could lead to an error that may be hard to track unless you know you’re looking for it. I usually disable this feature, and use the app’s ‘launched’ handler to do a ‘show window"someWindow"’ to manually show my window at startup. That way I know that all objects have been properly initialized, and that all connections have been made before trying to reference objects.
What I would do is something like this semi-pseudo-code…
on launched theObject
show window "yourMainWIndow"
tell window "progress_window"
show
tell progress indicator "progress" to start
--> Do stuff
tell progress indicator "progress" to stop
hide
end tell
end launched
on will open theObject
if name of theObject is "yourMainWIndow" then
--> initialize your main window here, BUT...
--> DON'T use the handler for this window to act as a delegate for another
else if name of theObject is "progress_window" then
tell theObject to center
--> Do any other init stuff
end if
end
The above assumes that you only want to run your progress window on startup. Since the launched handler ONLY executes once… at startup… this is a more appropriate place to put things that only occur at launch time. If you need to run the progress panel at other times, you could put your code into a subroutine, then call that from the launched handler.
That is perfect, thank you. Yes, I had planned on using the progress window other times, since there is typically a 1+ second lag whenever Palm Desktop is accessed, so I will take your advice and make it a subroutine.
Thank you for the clear explanations on the different handlers, and how they are called. That is extremely helpful. I still think that is a particular weakness for me; knowing how best to use the built in tools, based on how they operate and interact with one another.
Also, as per your advice from other communications, I am steadily working through learning Obj-C. Looks like a long term project…
One more thing, if I may. Everything is now functioning well, but I could not get it to work using the launched handler, so I used awake from nib instead, linked to the main window:
on awake from nib theObject
StartProgress("main")
set content of table view 1 of scroll view 1 of window "main" to GetAddrByCat()
StopProgress()
end awake from nib
The StartProgress handler is called in two other places, both from button clicks. The progress window pops up nicely in both instances, and it closes on schedule as well. These are the only three places from which the window is called (it is not a panel).
The curious behavior (which has been bugging me from the beginning, not just since these modifications) is that when the progress window is called from the on awake from nib (or before from the on will open) handler, the window is paler than when called from the button clicks, and the indeterminate progress bar is grey, and spinning SLOWLY. When called from the button clicks, it is a normal contrast window, blue/white progress bar, and spins what I would call normal speed. When I change it to the spinner, the behavior is similar, that is, the initial window is paler than normal, but in that case, the spinner seems to go just as fast as usual.
I have searched the ‘gray progress bar’ threads in this forum, but found nothing useful so far. This is not a major issue, but I am certainly curious about it. Any ideas are appreciated.
What you report is a quirk that I’ve found to exist only for windows with progress indicators in them. If you try to use a progress indicator in a window and have it open using awakefromnib or launched, it always exhibits this behavior, despite my attempts to get around it. A solution that seems to work around this is to use the ‘activated’ handler. The down side to this, is that the activated handler runs every time the app activates, such as when someone activates another app then comes back to it, or when someone clicks on the dock icon. To get around this, you have to keep a property variable that saves state for whether you can run the routine or not. I used the variable “canShowProgress”, which by default is true so it runs at startup. Then, the only extra step you need to take to accommodate using the activated handler is to set the variable to true right before you run the routine. I’m guessing that this all has something to do with the unarchiving order I mentioned in earlier posts. There must be something conflicting with the window or the indicator not yet being fully initialized, which doesn’t let it come to the front or activate properly.
property canShowProgress : true --> Must be set to true any time you want to run your 'progress' routine
on activated theObject
runCodeAndShowProgress()
end activated
on will open theObject
if name of theObject is "progressWIndow" then
tell theObject to center
end if
end will open
on choose menu item theObject
(* A sample menu item that runs the progress routine *)
if name of theObject is "RunProgress" then
set canShowProgress to true
runCodeAndShowProgress()
end if
end choose menu item
to runCodeAndShowProgress()
if (canShowProgress) then
set canShowProgress to false --> Clear the var so we don't show the routine on the next activation
(* Begin showing progress *)
tell window "progressWindow" to show
tell progress indicator "progress" of window "progressWindow" to start
(* Do all your stuff here *)
delay 4
(* End showing progress *)
tell progress indicator "progress" of window "progressWindow" to stop
tell window "progressWindow" to hide
end if
end runCodeAndShowProgress
Looks great, jobu, I will work on that this week. Are properties in AS Studio apps not remembered between runs? I don’t see where the canShowProgress property is re-set to true upon quitting the app, so I assume that every time the app is opened, everything is re-compiled anew, right?
Yes, asstudio projects do not by default save their property variables between runs. A new instance of the app and script is created on each run, so property variables do not carry over between runs as they do with plain applescripts. Every time you run the app, it loads the new instance, which should be first declared in the head of the file. Remember that applescript works from the top down, so you should always declare your variables at the very top, in the order you want them initialized. In this case, you want it to be set to true every time the app launches, which is it’s default behavior. If you wanted to store persistent variables that retain their vallues between runs, you would want to use the ‘user defaults’ system.