How can I get text from a text field with an applescript xcode project - xcode

I am trying to write an xcode app with applescript. I need to get user inputed text from a text box and set is as a variable when the submit button is pressed.
Thank You

I too am just getting to grips with Cocoa-Applescript (and there's not all that much info around!) but it should work as follows, at least this is how I've done it in my app :)
1) Create an outlet for the text field:
i.e. underneath:
script AppDelegate
property parent : class "NSObject"
add:
property myTextField : missing value
The 'missing value' bit is what makes myTextField available in Interface Builder.
2) Create a handler for your button:
on submitButtonClicked_(sender)
end submitButtonClicked_
(name it anything you like, but as far as I know it has to start with a lowercase letter and end with an underscore)
3) Link the handler and outlet to their respective UI elements:
In Interface Builder, right-click the App Delegate, and drag the circle next to submitButtonClicked onto your button
Likewise drag the circle from myTextField to the text field
4) Add a line in the click handler to set a variable to the value of the field:
on submitButtonClicked_(sender)
set currentTextFieldText to myTextField's stringValue() as text
-- do stuff with currentTextFieldText
end submitButtonClicked_
And if you wanted to put something in the text field:
tell myTextField to setStringValue_(whatYouWantInTheField)
Hope this helps!

Related

How can I determine what part of text in a scroll view is visible on screen from an Xcode UI test?

I'm new to the Xcode User Interface testing framework. I can successfully manipulate the screen elements, but cannot work out how to produce a meaningful assertion about what text is visible in a scrolling view.
The test I would like to write would go as follows: launch the app, type lots of text into a text view (enough that the first line scrolls out of view), assert that the first line of text is not visible, scroll the view back up to the top, then assert that the first line is now visible. Note that the purpose of this test is to ensure my app has wired things up correctly, not to test Apple's code.
XCUIApplication allows me to type into my NSTextView instance, and also allows me to scroll the associated NSScrollView. But how do I assert whether the first line of text is currently visible? The value attribute on XCUIElement provides the entire text content of the view, whether or not it is currently displayed.
The accessibilityRange(forLine:) and accessibilityString(for:) methods on NSTextView would be ideal, but I can't see how to access them as the UI test only has access to an XCUIElement, not the underlying NSTextView.
Have I missed something, or is there a better way to approach this?
If you set the accessibility identifier in the storyboard or in code for the text view you can get the text view via (assuming you gave it the id "textview1" and the window it's in has the default accessibility identifier of "Window"):
let textview1TextView = app.windows["Window"].textViews["textview1"]
but that won't actually get you what you need.
Instead, set the accessibility identifier of the scrollview and get that:
let scrollview = app.windows["Window"].scrollViews["scrollview1"]
Then use that to get the scrollbars (you should only have one in this case; you can use scrollbars.count to check.
let scrollbars = scrollview.scrollBars
print("scrollbars count: \(scrollbars.count)")
Then you can use the value attribute of the scrollbar to get it's value:
(you're converting a XCUIElemenTypeQueryProvider into an XCUIElement so you can get it's value):
let val = scrollbars.element.value
it will be 0 at the top and a floating point value when scrolled (one line of text in my test code showed a value of {{0.02409638554216868}}.
Documentation that will help you explore further:
XCUIElementTypeQueryProvider
XCUIElementAttributes
Note that you can put a breakpoint in the middle of your test, run it and then use the debugger console to examine things:
(lldb) po scrollbars.element.value
t = 749.66s Find the ScrollBar ▿ Optional<Any>
- some : 0
(lldb) po scrollbars.element.value
t = 758.17s Find the ScrollBar ▿ Optional<Any>
- some : 0.05421686746987952
and while in the debugger you can even interact with your app's window to scroll it manually (which is what I did between typing in those two po calls), or perhaps add text and so on.
OK OP now noted that they're interested in the specific text showing or not rather than the first line in view or not (which is what I previously answered above).
Here's a bit of a hack, but I think it'll work:
Use XCUICoordinate's click(forDuration:, thenDragTo:) method to select the first line of text (use the view frame to calculate coordinates) and then use the typeKey( modifierFlags:) to invoke the edit menu "copy" command. Then use NSPasteboard methods to get the pasteboard contents and check the text.
Here's a quick test I did to validate the approach (selecting the first line of text using XCUICoordinate as noted above is left as an exercise for the reader):
NSPasteboard.general.clearContents()
// stopped at break point on next line and I manually selected the text of the first line of text in my test app and then hit continue in the debugger
textview1TextView.typeKey("c", modifierFlags:.command)
print( NSPasteboard.general.pasteboardItems?.first?.string(forType: NSPasteboard.PasteboardType.string) ?? "none" );
-> "the text of the first line" was printed to the console.
Note that you can scroll the selection off screen so you have to not scroll after doing the select or you won't be getting the answer you want.

Xcode Applescript create list of results

I have been trying to work out the best way to accomplish this and every time I think I am on to something it doesn't seem to work in my situation.
If someone could point me in the right direction to an existing example or the correct google term I would be very grateful.
I am creating a Cocoa - Applescript Application in Xcode 5.
I have the basics in already, which so far prompts the user to select an audio track, the track is then played back in Quick Time and I have a button to return the current play time of the track, as it stands at the moment this returns the time to a variable of SMPTE ala.
tell application "QuickTime Player"
set SMPTE to get current time of document 1
end tell
My problem is what to do with the result of "SMPTE"
I would like to generate a list in a separate window with each button press updating a new row with the new returned value.
I have tried using a NSTableColumn but can't work out how to "auto fill" with each subsequent button press.
A very simplistic way.
Add an NSArrayController to the IB Objects.
Connect it to an outlet.
Select the TableView's TableColumn and go to it Bindings Inspector.
Bind it's Value to Array Controller
And name it's model key path as 'time'
In the TableColumn's Attributes Inspector. Set it's Title to 'time'
The code would be like this:
property ArrayController :missing value
on addTime_(sender) --clicked to add time
tell application "QuickTime Player"
set SMPTE to get current time of document 1
end tell
ArrayController's addObject:{|time|:SMPTE}
end addTime_
The Button would need to be connected to the Action: addTime:
To remove an item:
Simply add a new button and connect it to the ArrayController's Remove Action method.
( By dragging the button's connection to the ArrayController object in IB and selecting remove: )
To Save the data to be able to see it on relaunch:
Select the ArrayController object in IB and go to it's bindings inspector.
Bind it's Control Content's content Array to the 'Shared user defaults Controller'
And name it's model key path as 'theValues'
There is a very good intro tutorial here
And NSArrayController's Docs

How do I populate a popup button with AppleScript?

I've found this snippet of code in various place around the 'net:
tell window 1
tell menu of popup button 1
delete every menu item
repeat with catListItem in catList
make new menu item at end of menu items with properties {title:catListItem}
end repeat
end tell
end tell
When I use it in my AppDelegate script in a Cocoa-AppleScript Application, Xcode gives me an error: *t2t_AppDelegate.applescript:25: error: Expected end of line but found identifier. (-2741)* (Line 25 is "tell menu...")
I'm not sure what I'm missing that would allow me to dynamically populate the popup button with a list of terms (catList) that I'm drawing from another application. Any suggestions?
Unless you are running something earlier than Snow Leopard, It looks like you are using AppleScript Studio terminology (which was deprecated in Snow Leopard). Using the current AppleScriptObjC framework, the user interface items are referenced via outlet properties, for example:
property myPopUp : missing value
From the Interface Editor, this property is connected to your popup button, which allows you to use it with various methods in the NSPopupButton class and its parents, such as addItemsWithTitles. Once everything is defined and connected, you would use something like:
set catList to {"next item", "another item", "Items added"}
myPopUp's addItemsWithTitles_(catList)

Applescript and Microsoft Word

I'm working on a applescript to update the content of a document in Microsoft Word. The updating process is quite long (might take more than 5s). So I want to prevent users to change anything during the updating. Do you know whether Microsoft or Applescript a function like that?
In Windows, I can just display a User Form (which is a dialog telling that "we are updating... ") and close that form when it's done. However, I don't know whether I can do the same in Mac (with Applescript alone).
When you say "applescript", I don't know if you mean "plain" applescript or the AppleScriptObjC version. If you mean the latter, then I know ways to do it.
One way I've used during slow processes is to put an overlay view over the whole content view of the window. I make it translucent white to partially obscure the window, and put some kind of message (and maybe a progress indicator) on it. You can just use an NSBox (of the custom type) in IB to make this, and then make a subclass of NSBox to color the view and override mouseDown:. MouseDown:, doesn't need to have any code in it, just by overriding it, you capture any key and mouse events so they don't accumulate on the event queue, and get used by the view below after your overlay goes away. Here's code I've used:
script Overlay
property parent : class "NSBox"
on awakeFromNib()
set overlayColor to current application's NSColor's colorWithCalibratedWhite_alpha_(1,.8)
setFillColor_(overlayColor)
end
on mouseDown_(theEvent)
--log "mouseDown"
end
end script
I have this view as the top most view in the view hierarchy, and set its hidden property to true until I want to show it.

Define the class of the sender when making an IBAction connection in Xcode 4,2.1

In Xcode 4 or above, it has a handy function allowing us to CTRL + drag an object from the interface to the .h file to quickly connect the object with an event method (assume the Assistant Editor is enabled).
Say we have an UIButton in the interface, and we want to add an IBAction for its "touch up inside", we enable the assistant window and press/hold CTRL + Drag the button to the .h file to quickly generate the necessary codes.
In the popup prompt box, say we set "connection" as "Action".
In the "Type" drop-down, we can select "id" or "UIButton". <--- this is where my problem is.
The strange thing in Xcode 4.2.1 is: no matter what I select, it always generates code: "(id)sender" as the argument.
I know it is easy to manually change it to "(UIButton *) sender", but what is the point of this drop-down when it always generates "(id)"?
Is this is a bug of Xcode or am I missing something to make it directly generate the code "(UIButton *) sender" when I select "UIButton" in this drop-down?
Edited on 27/Feb/2012: This is confirmed solved in Xcode 4.3
- (void)action:(id)sender is just the way actions are defined. you can, in theory, connect different UI elements to the same action. after you've created the connection, you can manually change id to whatever class you want, or just do a cast inside the method.

Resources