I'm doing an applescript cocoa app and I'd like to run a function as a notification with the name "Finished Downloading" is displayed.
The function changes a value displayed in the main window of the cocoa app and the notification is created with a terminal command line.
I've tried to use observers but couldn't really understand how they work so, even if it's probably the right thing to use, I couldn't get it to work.
property NSNotificationCenter : class "NSNotificationCenter"
script AppDelegate
property parent : class "NSObject"
on myFunction()
log "hey"
end myFunction
on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
set ws to workspaceClass's sharedWorkspace()
set nc to ws's notificationCenter()
tell nc to addObserver_selector_name_object_(me, "myFunction()", "Finished Downloading", missing value) --tried this
end applicationWillFinishLaunching_
end script
As the notification named "Finished Downloading" is displayed in the top right corner of the monitor this script should run myFunction
Hope for help, thanks.
Alex
EDIT: thanks to the answer of Willeke I now verified that it's not possible to accomplish what I was trying to do. See Observe for new System Notifications OSX
Related
I am using the ruby gem gtk2 to display a simple file dialog, where the user can select a file from his computer. It works just fine, however there is one little problem.
The file dialog doesnt close after selecting the file, but it stays open until the whole script finished.
My file dialog looks like this:
def ask_for_file(question)
dialog = Gtk::FileChooserDialog.new(question, nil,
Gtk::FileChooser::ACTION_OPEN,
"gnome-vfs",
[Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT],
[Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL]
)
if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
file_name = dialog.filename.to_s
return file_name
else
return nil
end
end
When I call it in my script like this:
path = ask_for_file("Test?")
sleep(5)
puts "continue with #{path}"
The file dialog stays open for 5 seconds and is unresponsive in that time. How could I get it to close after a file has been selected, but before the 5 second sleep?
I tried to use dialog.destroy in ask_for_file just before returning the file_name but that didnt seem to help.
I solved it by creating a new window with a button to open the file dialog. Upon clicking the open button, I also send a signal to destroy the main window. This way everything closes immediatly after I selected a file.
For reference see this example
You need to manually call gtk_widget_destroy() on GTK+-provided dialog boxes like GtkFileChooserDialog; clicking on one of the buttons won't be enough. Note that this destroys the file chooser part of the dialog as well, so be sure to get your filename and anything else of value out before you do.
I want to make my own window, using Glade (3.14.2).
At a certain point in my program, I want to
1) Put up the window and let the user do stuff
2) Wait for it to close
3) Get values from the window object
4) Continue on in my code
So basically, I want to treat the window like a modal dialog - but one that I write and control.
I've tried for a few hours. The window appears just fine, as designed in Glade. The user can interact with it.
When the window closes, code that's been connected with signal_connect('destroy') executes.
But the code that invoked the window's show() method... does not continue executing after the window closes.
class GrammarNodeEditor
#this makes the class visual:
include GladeGUI
def initialize(raw_node = nil, &close_block)
#raw_node = raw_node || {type: :Sequence, data: []}
#original_data = #raw_node[:data]
#close_block = close_block
end
def show
puts "GNE Window Opening"
load_glade(__FILE__)
#builder["window1"].title = "Edit/Create Grammar Node"
#builder["window1"].signal_connect('destroy') {|*args|
#close_block.call(self)
puts "GNE WINDOW DESTROY"
}
show_window()
puts "Done showing window"
end
Here is how I invoke it:
rhs_editor = GrammarNodeEditor.new {|obj|
puts "In closeblck, obj is #{obj.inspect}"
#rhs = obj.raw_node
}
puts "About to call show in GR:Init"
rhs_editor.show
puts "Back from calling show in GR:Init"
Here is the output:
About to call show in GR:Init
GNE Window Opening
In closeblck, obj is #<GrammarNodeEditor:0x7b82a88 #raw_node={:type=>:Sequence, :data=>[]}, [more junk here]>
GNE WINDOW DESTROY
The first two lines of output appear after I open the window. The 3rd and 4th appear when I close the window.
Note that "Done showing window" and "Back from calling show in GR:Init" are not printed at all.
Just to make this a little more interesting, I want to be able to do this from within code that puts up another window. My top-level window has a button to create a new Rule. The Rule must be initialized with a Node, and then the Rule must be edited. So first I need to put up a Node-definition window (as shown above) and then, when I have a Node defined, I want to put up a Rule window that uses that Node.
So I think I need to call this code within either the initialize() or the show() method of the GrammarRuleWindow class (another Glade-defined window).
Can someone explain why my puts's aren't being printed, and how to make the control flow go on through them?
Thanks!
...So it turned out the problem was that I had created the window's .glade file directly in Glade, rather than using the VisualRuby IDE.
Creating the .glade in VR adds some stuff to the file that VR needs. Specifically, the file needs to contain the line
<signal name="destroy" handler="destroy_window" swapped="no"/>
before the first <child...> tag.
I am coding Mac App on Xcode with Applescript.
I made a function that doesn't stop forever, but I can't stop it.
It starts when I push a button that is located on the window.
Because this function doesn't stop, the button appears pushed forever.
And I have to force quit with 'Command+Option+Escape'. (Even if you do this activity, this app may not be stop.)
I want release the button before the function starts, and I want to stop this function safely with pushing another button.
This is my example. To stop this, push the "Stop" button on Xcode.
property parent : class "NSObject"
property mylabel : missing value
on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_
on myStartButtonHandler_(sender)
my myForeverFunction()
end myStartButtonHandler_
on myStopButtonHandler_(sender)
--How can I stop "myForeverFunction"?
end myStopButtonHandler_
on myForeverFunction()
set a to 0
repeat 100 times
set a to a+1
mylabel's setStringValue_(a)
delay 1
end repeat
end myForeverFunction
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
This is the project file --> https://dl.dropboxusercontent.com/u/97497395/test.zip
Sorry I am Japanese, I can't write English very well.
Basically the interface of your application is controlled and updated on your apps main thread. Therefore if you run some code which ties up the main thread then your interface will not have a chance to update itself until the code is complete. So to fix that you run the code in a background thread and thus your interface will be able to update itself.
I don't know if you can do this in AppleScriptObjC because I'm not too familiar with it. Here's how I do it in objective-c. I create a handler (someHandler) and then run this code. Note that since this handler isn't run in the main thread which has an automatically generated release pool, you will have to create and drain a release pool in your handler.
[NSThread detachNewThreadSelector:#selector(someHandler) toTarget:self withObject:nil];
EDIT: Here's the autorelease pool you asked about. In a reference-counted environment do it this way...
-(void)someHandler {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// do your stuff here
[pool drain];
}
With Automatic Reference Counting (ARC) you would do it this way...
-(void)someHandler {
#autoreleasepool {
// do your stuff here
}
}
So I'm not sure which applies to AppleScriptObjC. A quick google search turned up this post.
Right now your code is looping and looping and important things like the interface are never getting updated. If you call a doEventFetch function to run all of the queued processes, that should fix your problem. Just call it once every loop:
on doEventFetch()
repeat
tell current application's NSApp to set theEvent to nextEventMatchingMask_untilDate_inMode_dequeue_(((current application's NSLeftMouseDownMask) as integer) + ((current application's NSKeyDownMask) as integer), missing value, current application's NSEventTrackingRunLoopMode, true)
if theEvent is missing value then
exit repeat
else
tell current application's NSApp to sendEvent_(theEvent)
end if
end repeat
end doEventFetch
on loopFunc()
repeat
#Repeat stuff here...
doEventFetch()
end repeat
end loopFunc
I am trying to implement a Progress bar update in AppleScriptObjC. I have connected the progressbar thru IB and trying to increment the Progressbar update via incrementBy(5). The Inderterminate property is set to false. the IB connection is fine because if I set the Inderterminate to true and uncomemnt the code to start/stop animation it works fine. this is the Error I get "-[NSProgressIndicator incrementby:]: unrecognized selector sent to instance 0x2007e2220"
following is the code
property ProgressBar : missing value
on MyBtnClick_(sender)
(*.. some code ..*)
ProgressBar's incrementby_(5)
ProgressBar's displayifNeeded()
--ProgressBar's startAnimation_(me)
--ProgressBar's stopAnimation_(me)
end MyBtnClick_
Thanks in Adv for any pointers.
regards,
Jesse
Try incrementBy_ -- case matters.
Ok so, "unrecognized selector sent to instance" means that the command sent is unknown so the command your sending to it means it does not exist, however If you are trying to send a message to make the progress bar to set its progress % then, i can help you! :D, I use the "setDoubleValue" command to set the Progress bars status and you don't need to startAnimation and stopAnimation it either :D
ok so here is a script that will store the current progress and when MyBtnClick is run, it will add 5% to the progress bar
property ProgressBar : missing value
property currentProgress : 0
on MyBtnClick_(sender)
(*.. some code ..*)
set currentProgress to currentProgress + 5
ProgressBar's setDoubleValue_(currentProgress)
end MyBtnClick_
hope this helps :D
Can anyone tell me if there is a way for me to use a variable within a lump of code, so that code can be looped to send messages to multiple objects?
For example, if I have 10 buttons and want each to send a variation of the same command 'sendCommandX', with X being the number of the button.
Right now I have 10 separate messages, and each button calls its own, like
on mouseUp
sendCommand1
end
on mouseUp
sendCommand2
end
Each of these 10 sendCommand# messages do the same thing, just with a different number in them.
It would be great if I could use a variable within the call, so I could have one reusable message. Like:
on mouseUp
sendCommandX (X being the number of the button clicked)
end
and then the sendCommandX could use the same variable within, like
on sendCommandX
echo "you clicked button X:
end
send the number as a parameter:
-- on Button 1
on mouseUp
sendCommand 1
end
-- on Button 2
on mouseUp
sendCommand 2
end
-- movie script!
on sendCommand which
-- use 'which' here, e.g.
put "You pressed button " & which
end
I guess your button scripts are cast member scripts?
This code would be better as a behavior, because then you'd only need one script. But it will work ok like this.