Cocoa : How to make multiline NSTextField? - objective-c

How to make multiline NSTextField? UPDATE: I've found in IB special type of NSTextField called "Wrapped Text Field". It is multiline but when I want get a newline I have to press Ctrl+Enter. But I want to press only Enter to get a newline. How can I do it?

There is no way to specify this behavior solely in Interface Builder. You can do it with a delegate message as described in this tech note QA1454.
Here is the example delegate message from the tech note:
- (BOOL)control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)commandSelector
{
BOOL result = NO;
if (commandSelector == #selector(insertNewline:))
{
// new line action:
// always insert a line-break character and don’t cause the receiver to end editing
[textView insertNewlineIgnoringFieldEditor:self];
result = YES;
}
else if (commandSelector == #selector(insertTab:))
{
// tab action:
// always insert a tab character and don’t cause the receiver to end editing
[textView insertTabIgnoringFieldEditor:self];
result = YES;
}
return result;
}

Using NSTextView, its a multiline NSTextField sorta, it is a subclass of NSText correct my if I am wrong. The NSTextView has an NSTextStorage, which is a subclass of NSAttributedString. You need to give it an NSAttributedString object instead of a NSString to fill its contents as it can display colors etc.
[[yourTextView textStorage] setAttributedString:attrStr];

Related

How to discover each UI object sent the message

I am still learning Objective C/Cocoa and I am building a program with a simples interface. In this interface, there are some NSTextField which has this delegate:
- (void) controlTextDidChange: (NSNotification *) obj{
//Some code here
}
When the user changes the the text of any of these NSTextField the program needs to check if the number inside the NSTextField is an integer. If the provided string is not an Integer I want to display a dialog with the error and each NSTexField the error occurred, since I have more than one NSTextField connected to this method.
My question is: how can I discover each UI object sent the message to the controlTextDidChange method?
Thanks in advance.
- (void)controlTextDidChange:(NSNotification *)anotif
{
if ([anotif object]==field1)
{
// field1 processing
}
else
{
// field2 processing
}
}
From
controlTextDidChange with 2 nstextfields - call different selectors
If you don't have the UITextField subviews as properties, you can set tag for every UITextField subview change the code #Bruno provided as follows:
- (void)controlTextDidChange:(NSNotification *)anotif
{
UITextField *textField = (UITextField *)[anotif object];
if (textField.tag == 1)
{
// field1 processing
}
else
{
// field2 processing
}
}

How to properly use delegation for NSTextField

Im trying to implement a delegate for a NSTextField object so I can detect the user input in real time and give some feedback about no allowed input in that particular field.
Especially, I want to simulate the onChange() method from JavaScript, detecting the user input in real time and show him a warning if it is writing a non supported value.
i.e. The app have a text field it only accept numeric values from 0 to 255 (like RGB values) and I want to know when the user is writing not numeric values or out of range values to instantly show him a warning message or change the text field background color, just a visual hint to let him know the input it's wrong.
Like you see on the pictures above, I want to show a warning sign every time the user inputs a forbidden value in the text field.
I have been reading a lot of the Apple's documentation but I don't understand which delegate to implement (NSTextFieldDelegate, NSTextDelegate, or NSTextViewDelegate), also, I have no idea how to implement it in my AppDelegate.m file and which method use and how to get the notification of user editing.
Right now, I already set the Delegate in my init method with something like this [self.textField setDelegate:self]; but I don't understand how to use it or which method implements.
I found a solution using the information posted in this question... Listen to a value change of my text field
First of all I have to declare the NSTextFieldDelegate in the AppDelegate.h file
#interface AppDelegate : NSObject <NSApplicationDelegate, NSTextFieldDelegate>
After that, I have to instantiate the delegate for the NSTextField object I want to modify while the user update it in the AppDelegate.m file.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[self.textField setDelegate:self];
}
Finally, I implement the methods to detect field editing with the changes I want to set.
- (void)controlTextDidChange:(NSNotification *)notification {
NSTextField *textField = [notification object];
if ([textField doubleValue] < 0 | [textField doubleValue] > 255) {
textField.textColor = [NSColor redColor];
}
}
- (void)controlTextDidEndEditing:(NSNotification *)notification {
NSTextField *textField = [notification object];
if ([textField resignFirstResponder]) {
textField.textColor = [NSColor blackColor];
}
}
Make your class conform to the NSTextFieldDelegate protocol. It need's to be that protocol because in the documentation it says the type of protocol the delegate conforms to.
#interface MyClass : NSObject
And implement the delegate's methods (just add them to your code). Example
- (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor
{
}
EDIT:
I think in your case it would be better to replace the TextField for a TextView and use a NSTextViewDelegate, in the delegate, the method of most interst of you should be
- (BOOL)textView:(NSTextView *)aTextView shouldChangeTextInRange:(NSRange)affectedCharRange replacementString:(NSString *)replacementString
{
BOOL isValid = ... // Check here if replacementString is valid (only digits, ...)
return isValid; // If you return false, the user edition is cancelled
}

UITextField editingChange Control Event not works

I have some textfields and I want to do when I change textfield1 text set text to other textfields. My code below. But it not works. How can I solve this?
- (IBAction)TCKimlikTextChange:(id)sender {
[TCKimlikText addTarget:self action:#selector(yourMethod: ) forControlEvents:UIControlEventEditingChanged];
}
-(void)yourMethod: (UITextField*)tf_{
if (tf_) {
if (TCKimlikText.text == #"1") {
AdinizText.text = #"Hacer";
}
}
}
Your code is very abstract. yourMethod, tf_ TCKimlikTextChange are all expressions that are not very human readable. You should work on your variable names.
I suppose your first method is a button handler. It just assigned a target and action to the text field, but does not call any method. You do not need that action if you use the delegate protocol.
To solve your problem: implement the UITextField delegate methods. Make sure you set the delegate (probably self) for your text fields. Your view controller must mention the <UITextFieldDelegate> protocol in its .h file. Thus, in textField:shouldChangeCharactersInRange:replacementString::
if ([textField.text isEqualToString:#"1"]) {
displayLabel.text = #"Hacer";
}
Notice that you need isEqualToString: to compare strings, a simple == won't do.
If u are want to change on the click of the return button use the delegate
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if(textField == field1)
[field2 setText:field1.text];
[field1 resignFirstResponder];
return YES;
}
or u can use other delegates too like:
– textFieldShouldBeginEditing:
– textFieldDidBeginEditing:

UISearchBar select all text

Is there any way to select all text in UISearchBar?
I tried [searchBar selectALL:], but it throw the signal (unrecognized selector).
I want to allow user to alter previous search text. At the some time, when user just starts typing new request, the old one should be dismissed. The standard way how to achieve it - select all text at the moment when text begin editing.
This can be accomplished using the standard UIResponder semantics. No need to dig down into the private view hierarchy of UISearchBar.
[[UIApplication sharedApplication] sendAction:#selector(selectAll:) to:nil from:nil forEvent:nil]
You can call this from anywhere, and the selectAll: selector will run the responder chain to see if any objects respond to it. Assuming your search bar is currently the first responder (if the user is typing in it), it will respond and the result will be all text selected. If not you can make it the first responder by calling becomeFirstResponder on the search bar.
[_mySearchBar becomeFirstResponder]
[[UIApplication sharedApplication] sendAction:#selector(selectAll:) to:nil from:nil forEvent:nil]
If you want the 'type to replace' functionality that selecting the text in the UITextField gives you (ie the extra tap on the cross is unacceptable), you can dig through the subviews of the UISearchBar to find the UITextField (or UISearchBarTextField) and select its text:
// need to select the searchBar text ...
UITextField * searchText = nil;
for (UIView *subview in searchBar.subviews)
{
// we can't check if it is a UITextField because it is a UISearchBarTextField.
// Instead we check if the view conforms to UITextInput protocol. This finds
// the view we are after.
if ([subview conformsToProtocol:#protocol(UITextInput)])
{
searchText = (UITextField*)subview;
break;
}
}
if (searchText != nil)
[searchText selectAll:self];
In my case, the sending selectAll(_:) didn't work immediately after calling becomeFirstResponder.
I worked around it by waiting one runloop:
Swift 2:
dispatch_async(dispatch_get_main_queue()) {
UIApplication.sharedApplication().sendAction(#selector(UITextField.selectAll(_:)), to: nil, from: nil, forEvent: nil)
}
Swift 3:
DispatchQueue.main.async(execute: {
UIApplication.sharedApplication().sendAction(#selector(UITextField.selectAll(_:)), to: nil, from: nil, forEvent: nil)
})
Here is another suggestion: when someone activates the search bar, there are two possible intentions: type new text or add to the existing text. I think you should give your user the choice.
If he wants to add text he naturally taps again at the end of the existing text.
If he wants to start over, he can press the clear button that automatically appears when the search bar becomes active.
Swift 4
If you want to select all text when searchBar become first responder.
func searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {
DispatchQueue.main.async {
UIApplication.shared.sendAction(#selector(UITextField.selectAll(_:)), to: nil, from: nil, for: nil)
}
return true
}
I dont think there is a method to select all text. Maybe when there is a focus on UISearchBar you can clear the search bar like so - searchBar.text = #""
i.e. clear text in the search bar... Hope this helps in some way...
You can accomplish this by keeping a BOOL indicating if editing the search bar text field just started. Then, you can catch the first key press in the searchBar delegate methods.
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
firstEdit = YES;
}
- (BOOL)searchBar:(UISearchBar *)searchBar
shouldChangeTextInRange:(NSRange)range
replacementText:(NSString *)text {
if (firstEdit) {
searchBar.text = text;
firstEdit = NO;
}
return YES;
}

call a method with the "Return" (Done) Button of the keyboard

is there anyboby who can give me an example method that is called by pressing the return button of the keyboard and saves the text of a textview (that was typed in before) in the nsuserdefaults?
thanks a lot :)
Make sure your UITextField has a return key type set to UIReturnKeyGo (this is for the image on the keyboard):
theTextField.returnKeyType = UIReturnKeyGo;
Then use this method to do what ever you want to do:
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
// Tell the keyboard where to go on next / go button.
if(textField == theTextField)
{
// do stuff
}
return YES;
}
To get the text from the textfield just call theTextField.text and save as you wish!
Swift Version
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
// Tell the keyboard where to go on next / go button.
if textField == theTextField {
// do stuff
}
return true
}
If you are adding UITextField to an UITableCell dynamically, you need to also set delegate for it:
self.textfield.delegate = self;
also on the the header file you need to add this:
#interface YourController: UIViewController <UITextFieldDelegate>