I have a 3 text fields and a button. I want to press on the first uitextfield, press on the button and hello world to be pasted, and same goes to the others. I know how to do this, but my method is too basic and I need to keep the same pasting code .. (so I guess in a way what im asking is, how can I retrieve the uitextfield that the user presses so I can alter it)
this is what i do:
if ( textfield1.isEditing ) {
textfield1.text = ...
}
Is there a way I can get rid of the variable textfield1, because if I have 1000 textfields I will have to write 1000 lines .. I can do loops but I want to retrieve the value somehow maybe using the sender? (new to xcode).
I think if you implement the textFieldDidBeginEditing function:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
// process text
}
and set the delegate of your text fields to the viewcontroller that contains this function. The input parameter textField should be the textfield that you are currently editing. This way you wont have to do the 1000 lines of code you mentioned.
Related
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.
I have a simple desktop app where a TextField should be focused when the window loads. I have this working, but it's a little annoying that, having loaded the users content into the TextField, the entire contents of the field become selected automatically. The user may want to start editing the content, but they will rarely/never want to replace it all at once (imagine a text editor doing this, to see what I mean).
I see there is an Action for selectAll: but what I want is the opposite Action of selectNone:
I tried passing nil to the selectText method, but that doesn't work:
textField.selectText(nil)
I found a number of answers on StackOverflow that mention a selectedTextRange, but this appears to be outdated, because Xcode 6.3 doesn't recognize this as a valid property on TextField.
Can anyone explain how I do this?
It's been a while since I've dealt with NSTextFields to this level (I work mostly in iOS these days).
After doing a little digging I found this on the net:
NSText* textEditor = [window fieldEditor:YES forObject:textField];
NSRange range = {start, length};
[textEditor setSelectedRange:range];
window is the window containing your field, textField.
This requires the field editor to be managing your field, what can be done simply by previously selecting the whole text of the field using the selectText:sender method.
Here is the final swift code that I got working based on what Duncan C posted:
if let window = NSApplication.sharedApplication().mainWindow {
let textEditor = window.fieldEditor(true, forObject: textField)!
let range = NSRange(0..<0)
textEditor.selectedRange = range
}
I have many NSTextFields and I want to know, if the user has pressed one of the arrow keys while editing one of them. The function
override func keyDown(theEvent: NSEvent) {
switch theEvent.character {
case NSRightArrowFunctionKey:
println(1)
moveGor(NSRightArrowFunctionKey)
case NSLeftArrowFunctionKey:
moveGor(NSLeftArrowFunctionKey)
case NSUpArrowFunctionKey:
moveVert(NSUpArrowFunctionKey)
case NSDownArrowFunctionKey:
moveVert(NSDownArrowFunctionKey)
default:
super.keyDown(theEvent)
}
}
doesn't seem to work. Is there any other way to do that in swift?
EDIT:
I have the extension for NSEvent:
extension NSEvent {
var character: Int {
let str = charactersIgnoringModifiers!.utf16
return Int(str[str.startIndex])
}
}
that I used in previous function
When text fields have the focus, they actually don't. Instead, a text view is added to the window on top of the text field and that text view is the first responder and handles all of the input and editing behaviors. The text view is known as the "field editor". The text field does not receive key down events; the text view does.
You could substitute a custom text view as the first responder for the text field and have that text view handle the key down events specially. However, it's probably easier to take advantage of the fact that the text field is the delegate for the text view. Depending on exactly what you're trying to achieve, you might implement -textView:willChangeSelectionFromCharacterRange:toCharacterRange:, but that's not exclusively about arrow keys.
A more promising method might be -textView:doCommandBySelector:. That's also not really about the arrow keys, but in some ways it's better. The arrow keys, and all other standard editing keys, operate by being translated through the key bindings system into command selectors. The command selectors represent the semantic operation being performed, like -moveUp:. They are changed by modifier flags, so that Shift-up-arrow might generate -moveUpAndModifySelection:.
Anyway, in -textView:doCommandBySelector:, you can execute code based on the selector and either tell the text view not to do anything else (by returning YES) or let the text view do its normal thing in addition (by returning NO). (Obviously, return NO for anything that you don't care about.)
So I've set up an NSPopUpButton menu and populated it with the menu items and set all the key equivalents to what I want. The problem I'm having is that it automatically displays the key equivalent in the menu items next to the title of the item and I don't want it to. Is there any way to prevent it? I've searched the documentation and Google but can't seem to find anything about it.
the two ways that would come to mind would be to subclass NSMenuItemCell and do the following:
(untested, but seems like it should work)
- (NSRect)keyEquivalentRectForBounds:(NSRect)cellFrame
{
return NSZeroRect;
}
- (CGFloat)keyEquivalentWidth
{
return 0.0f;
}
or number 2 to remove the key equivalents and handle the events manually.
I have an NSTableView that allows inline editing on one of its cells (NSTextFieldCell). This actually works well, but I want to manipulate the content for the editing session.
Imagine having a string with a path (say: "folder/subfolder/myfile.txt") as the content of such a cell. But when the user enters edit mode for this cell (e.g. by double clicking) I want only the string "myfile.txt" to be editable (i.e. to appear in the editor). How can I achieve this?
You could create a custom NSFormatter that does this. Override the method stringForObjectValue: to return the full string and editingStringForObjectValue: to return only the part you want to edit. You also need to write a method getObjectValue:forString:errorDescription: to transform the edited string back to the complete string. How to exactly do this depends on the rest of your program. You somehow need to get back the part of the string you removed for editing.