I am trying to link my code to my GUI. But it won't let me.
Currently, I have a label, Button, and a Text Field on my GUI. This is my code for the GUI:
-- IBOutlets
property window : missing value
on buttonClicked_(sender)
display alert "Hello there " & (stringValue() of textField)
end buttonClicked_
on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
When I try using the App Delegate tool, It doesn't work. I drag it to the parts on the GUI and it makes a blue line. But, The only thing the shows up under "Outlets" is "Window"
If I run the program, The GUI comes up, but it doesn't do anything cause the code isn't connected!
How do I connect my code to my GUI?
Extra Info: Xcode 5.1
You have to declare the outlet and then connect the outlets in the xib. ctrl-drag (or click right mouse button and drag) from AppDelegate to the textfield.
Then ctrl-drag from the button to the AppDelegate and choose the method, you want to send.
-- IBOutlets
property window : missing value
property myTextField : missing value
on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_
on buttonClicked_(sender)
display alert "Hello there " & myTextField's stringValue
end buttonClicked_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
Related
I would like to know if it is possible to get the text output that is displayed in the terminal by running a shell script and display it in a Scrollable Text View, using applescript.
for example:
The output that the command: git clone https://github.com/torvalds/linux.git displays as shown in the image below would be displayed in a Scrollable Text view, would that be possible?
P.S:I'm sorry if the explanation was not clear, I hope someone understands and can help me!!
The steps for getting output from an asynchronous task like this are:
Create an
NSTask;
set its output to an NSPipe's fileHandleForReading;
register for a notification so you can get data to put into the textView as it becomes available.
To help with converting from Objective-C, Apple provided a conversion guide with their AppleScriptObjC Release Notes, but other than examples posted on various web sites and forums, that is about it. In general, for specific information about the various Cocoa classes and methods, you will need to look them up in Apple's documentation (for Swift you can switch to the Objective-C equivalent).
Note that an NSTextView does not have any terminal emulation (ANSI escape codes, etc), which is not trivial (take a look at iTerm2 for an example terminal application), so there won't be any cursor control. Git is also a little weird in that the progress uses standard error, so that will need to be redirected to standard output.
For a plain Xcode example, create a new AppleScriptObjC project and add the following statements to the AppDelegate:
property textView : missing value -- IBOutlet
property task : missing value -- this will be the NSTask
to startTask()
tell current application's NSTask's alloc's init() -- set up the task
its setCurrentDirectoryURL:(current application's NSURL's fileURLWithPath:(POSIX path of (path to desktop folder))) -- currentDirectoryPath deprecated in 10.13
set gitPath to "/Applications/Xcode.app/Contents/Developer/usr/bin/git"
its setExecutableURL:(current application's NSURL's fileURLWithPath:"/bin/zsh") -- launchPath deprecated in 10.13
its setArguments:{"-c", gitPath & " clone --progress https://github.com/torvalds/linux.git 2>&1"} -- combine stderr with stdout
its setStandardOutput:(current application's NSPipe's pipe())
its standardOutput's fileHandleForReading's readInBackgroundAndNotify()
set my task to it -- update script property
end tell
# set up notification observers
set notificationCenter to current application's NSNotificationCenter's defaultCenter
set readNotification to current application's NSFileHandleReadCompletionNotification
notificationCenter's addObserver:me selector:"dataAvailable:" |name|:readNotification object:(task's standardOutput's fileHandleForReading)
set terminateNotification to current application's NSTaskDidTerminateNotification
notificationCenter's addObserver:me selector:"taskTerminated:" |name|:terminateNotification object:task
set {theResult, theError} to task's launchAndReturnError:(reference) -- |launch| deprecated in 10.13
if theError is missing value then
log "Task Launched"
else
log "Error launching task: " & (theError's localizedDescription() as text)
end if
end startTask
on dataAvailable:notification -- get some output from the task
set theData to notification's userInfo()'s objectForKey:(current application's NSFileHandleNotificationDataItem)
if theData is not missing value and theData's |length|() > 0 then showResult(theData)
notification's object's readInBackgroundAndNotify() -- notify again when more data is available
end dataAvailable:
to showResult(resultData) -- append data to the end of the text view
set resultString to current application's NSString's alloc()'s initWithData:resultData encoding:(current application's NSUTF8StringEncoding)
set attributedString to current application's NSMutableAttributedString's alloc()'s initWithString:resultString
set theFont to (current application's NSFont's fontWithName:"Menlo Regular" |size|:12)
set theRange to (current application's NSMakeRange(0, attributedString's |length|()))
attributedString's addAttribute:(current application's NSFontAttributeName) value:theFont range:theRange -- use monospaced font
textView's textStorage()'s appendAttributedString:attributedString
textView's scrollToEndOfDocument:me -- 10.14+
end showResult
on taskTerminated:notification
current application's NSNotificationCenter's defaultCenter's removeObserver:me
repeat -- get any early termination leftovers
set theData to notification's object's standardOutput's fileHandleForReading's availableData
if theData is not missing value and theData's |length|() > 0 then
showResult(theData)
else
exit repeat
end if
end repeat
set my task to missing value -- clear script property
log "Task Terminated"
end taskTerminated:
In the Interface Editor, add a scrollable text view to the main window and connect it to the textView property, edit the currentDirectory and gitPath locations as needed, and put a statement in the applicationWillFinishLaunching hander to call startTask().
For something a bit simpler (shorter) to test with that still has a little output, the task arguments can be changed to something like:
its setExecutableURL:(current application's NSURL's fileURLWithPath:"/usr/sbin/system_profiler")
its setArguments:{"-detailLevel", "basic"} -- mini, basic, full
-- or --
its setExecutableURL:(current application's NSURL's fileURLWithPath:"/bin/zsh")
its setArguments:{"-c", "find /Users/$USER -iname '*.scpt'" } -- find scripts
i have a very simple applescript app in xcode that just opens a window and has a button that redirects to a website. Is there a way to automatically exit the window if the user hasnt clicked the button in 60 seconds.
Here is my code
script AppDelegate
-- property parent : class "NSObject"
-- IBOutlets
property theWindow : missing value
on applicationWillFinishLaunching_(aNotification)
-- Insert code here to initialize your application before any files are opened
end applicationWillFinishLaunching_
on buttonClicked_(sender)
open location "https://example.com"
quit
end buttonClicked_
on applicationShouldTerminate_(sender)
-- Insert code here to do any housekeeping before your application quits
return current application's NSTerminateNow
end applicationShouldTerminate_
end script
Since the window is being shown when the application starts up, you can just call a method/handler after a delay from the applicationWillFinishLaunching method. Since you are also quitting from the button handler, that can perform double duty, for example, replace these handlers:
on applicationWillFinishLaunching_(aNotification)
my performSelector:"buttonCLicked:" withObject:me afterDelay:60
end applicationWillFinishLaunching_
on buttonClicked_(sender)
if sender is not me then open location "https://example.com"
current application's NSApp's terminate:me -- quit
end buttonClicked_
I have an applescript that captures a counter in another application. This works fine but I'd like to output the results to another floating window and have it update with each loop. Does anyone know of a way to do this? Complete newb.
Thanks
EDIT:
My code is:
tell application "System Events"
tell process "MIDI Editor"
with timeout of 0 seconds
repeat
set barCount to value of text field "Main Counter" of group "Counter Display Cluster" of window "Edit: kjhsdf" of application process "MIDI Editor" of application "System Events"
delay 0.01
end repeat
end timeout
end tell
end tell
(Not sure why that last end tell keeps breaking out of the code block!)
So its barCount that I want to mirror in real time in another window
From the Script Editor you can use some AppleScriptObjC to programmatically create a non-modal window with a text field that can be updated. In the example below I am using a repeating timer instead of an AppleScript repeat statement, as tight loops like that will block the user interface. Save the script as an application, with the option set to stay open.
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Cocoa"
use scripting additions
property WindowFrame : {{200, 600}, {150, 50}} -- window location and size
property TextFrame : {{10, 10}, {130, 30}} -- window size minus 20
property mainWindow : missing value
property textField : missing value
property timer : missing value
on run -- example
setup()
update()
set my timer to current application's NSTimer's timerWithTimeInterval:0.25 target:me selector:"update" userInfo:(missing value) repeats:true
current application's NSRunLoop's mainRunLoop's addTimer:timer forMode:(current application's NSDefaultRunLoopMode)
end run
to update() -- update text field
set barCount to ""
with timeout of 0.5 seconds
tell application "System Events" to tell process "MIDI Editor"
set barCount to value of text field "Main Counter" of group "Counter Display Cluster" of window "Edit: kjhsdf"
end tell
end timeout
textField's setStringValue:(barCount as text)
end update
to setup() -- create UI objects
tell (current application's NSTextField's alloc's initWithFrame:TextFrame)
set my textField to it
its setFont:(current application's NSFont's fontWithName:"Menlo" |size|:18)
its setBordered:false
its setDrawsBackground:false
its setSelectable:false
end tell
tell (current application's NSWindow's alloc's initWithContentRect:WindowFrame styleMask:1 backing:(current application's NSBackingStoreBuffered) defer:true)
set my mainWindow to it
its setAllowsConcurrentViewDrawing:true
its setHasShadow:true
its setTitle:"Progress"
its setLevel:(current application's NSFloatingWindowLevel)
its (contentView's addSubview:textField)
its setFrameAutosaveName:"Update Window" -- keep window position
its setFrameUsingName:"Update Window"
its makeKeyAndOrderFront:me
end tell
end setup
I have a script that, among other things, records the browser window it was activated on when it was launched. Things happen in the middle, and then the script needs to go back to the original window and tab it was called on.
Problem is, a user may change the active window or tab during the script's run. I want to return to the window and tab that was used when the script was called.
Here's how I'm trying (and failing) to do this:
tell application "Safari"
if (id of front window) is not (windowID of browserInfo)
display dialog "Made it in the block!"
display dialog (get index of window 1)
display dialog (get index of window (windowID of browserInfo))
-- ...
The dialogs are all for debugging, of course.
Now, browserInfo is an object whose windowID property corresponds to the Safari window where the script was called. This is usually something like '889' or '1195' or some other number.
Now, what's interesting is the first four lines fire properly when simulating a user that started in one window, then activated another. The fourth line returns '1', as expected. But the fifth line gives an error: Safari got an error: Can't get window 809. Invalid index.
How can I get the index of a Safari window when all I can use is an ID?
(And yes, URL and window title are fine things, but they are out of bounds for my application. Users may have multiple windows open with the same URL and window title. So I need the specific window ID.)
I believe this is what you're after...
on run
tell application "Safari"
set myID to id of window 1
set myTab to current tab of window 1
end tell
do shell script "sleep 8" -- simulates time where user may change tabs
tell application "Safari"
set index of window id myID to 1
set current tab of window 1 to myTab
end tell
end run
I'm trying to enable or disable all the control in a window as the programme changes from interactive to non-interactive mode. How can I ask a window to give me all its contents?
every control of window "mainWindow"
doesn't work, nor does
contents of window "mainWindow"
Actually, I haven't been able to find any good documentation for interacting with menu items from interface builder at all. Things like how to set the contents of popups, and buttons and so on.
thanks
The way I do it at the moment is:
property onlineControls: {"maxLength", "speed", "accelerationSlider", "accelerationField", "showInfo"} --and so on, listing all the controls by name
on enableControls(theList, enableState)
tell window "mainWindow"
repeat with theControl in theList
set the enabled of control theControl to enableState
end repeat
end tell
enableControls(onlineControls, true)
I've made several lists of controls tht get turned on or off depending on the state the programme is in. But it has to be hard coded, which I don't see as being the best way.
tell application "System Events"
tell process "Adium"
get entire contents of window 1
end tell
end tell
This script will give you as result all contents of front window of Adium: butons of window, tool bars of window, buttons of tool bars, etc. Enjoy =]
I haven't been able to find a way to get all the controls in a window, but here's an example of interacting with the menu of a popup button:
tell menu of popup button "somePopupButton" of window "mainWindow"
delete every menu item
repeat with i in someItems
make new menu item at end of menu items ¬
with properties {title:i, enabled:true}
end repeat
end tell
Is the same script as "BoB1990" with the possibility of getting back the information given by get entire contents of window in a string of whom you can observe or modify all the items listed :
tell application "System Events" to tell process "Adium"
set this_info to {}
try
display alert ((get entire contents of window (x as integer)))
on error errMsg set theText to errMsg
set this_info to do shell script " echo " & theText & " | sed 's#System Events got an error: Can’t make ##g;s# into type string.##g'"
end try
set info to {}
set info to do shell script " echo " & this_info
display alert (info)
end tell