Enabled binding for NSTextField bound to NSString - cocoa

#interface MyClass {
NSString *_myString;
}
#property (copy) *myString;
#end
#implementation MyClass
#synthesize myString = _myString;
- (void)awakeFromNib {
self.myString = #"";
}
In the nib, I have an NSTextField and an NSButton. The text field's Value binding is set to myClass.myString. I verified that the variable _myString is being updated correctly when text is typed into the text field.
The Enabled binding of the NSButton is set to myClass.myString.length. However, when I start up the program, the NSButton is enabled! If I go to the textfield and type something into it, the button stays enabled. Then if I erase the text from the textfield, the button becomes disabled.
But why isn't the button disabled to begin with, after the call in awakeFromNib ? Do I have to do some additional work to make the binding work in the opposite direction (myClass.myString --> NSTextField) ? I thought that declaring myString as a property would do the trick.

I'm not sure what is causing this but I would say the easiest way to fix it, since your text will start out empty, is in awakeFromNib do something like [myButton setEnabled:false];

Related

Can I get an Checkbox to visually change its state before sending its action?

I have an OS X app with two checkboxes (NSButton). If the first(primary) is unchecked, it disables and unchecks the second one.
Here is the code for that functionality,
#IBAction func peopleCheckboxAction(sender: AnyObject) {
if(self.peopleCheckbox.state == NSOffState){
self.peopleCommentsCheckbox.enabled = false
self.peopleCommentsCheckbox.state = NSOffState
}else{
self.peopleCommentsCheckbox.enabled = true}
}
But here's the thing: that code gets executed before the first checkbox's state is changed, and it create a two-step action that feels almost like the first box is being unresponsive, or perhaps the user has clicked the wrong button, since the second control changes first. It's only a beat off, but I'd like to fix it.
Is there a simple way to reverse the way these two things are executed, or to ensure that they're happening nearly simultaneously?
Try this:
[self.peopleCheckBox sendActionOn:NSLeftMouseDownMask];
(The default behavior is the action is sent on mouse up.)
You could see what kind of effect you get with bindings - which would mean doing away with the action method altogether.
You'd normally set it all up in Interface Builder (IB), but copying and pasting the code below will quickly let you see if this approach is responsive enough for your needs. If it is, you should probably make the effort to set it all up in IB, leaving you with just the peopleState property in code.
#import "AppDelegate.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSButton *peopleCheckBox;
#property (weak) IBOutlet NSButton *commentCheckBox;
#property NSNumber *peopleState;
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Each time you click on the peopleState checkbox,
// the value of the property <peopleState> will change.
[self.peopleCheckBox bind:#"value"
toObject:self
withKeyPath:#"peopleState"
options:nil];
// Each time the value of the property <peopleState> changes,
// the 'enabled' status of the commentCheckBox is updated
// peopleState == NSOffState -> commentCheckBox disabled.
[self.commentCheckBox bind:#"enabled"
toObject:self
withKeyPath:#"peopleState"
options:nil];
}
#end

How to set a variable from a text view and displaying it on a label

In my .h file I have set properties for both the text field and the label:
#property (retain, nonatomic) IBOutlet UITextField *phoneNumberEntry;
#property (retain, nonatomic) IBOutlet UILabel *testLabel;
I also synthesized them in the .m file:
#synthesize phoneNumberEntry;
#synthesize testLabel;
how would I save the content of the textview to a variable, and then display it to a label?
WHat you need to do is create a string variable to hold the text of the UITextField.
NSString *textString = phoneNumberEntry.text;
then all you have to do is set the text of the label using the string variable just created
testLabel.text = textString;
EDIT:
If you're having trouble hooking it up in IB, just go to the files owner, and then click on the identity inspector, and find the box that says "class:" or something similar. THis is where you're going to type in your class. Once typed in, just hit enter, and then go to the connections inspector. This will allow you to see the properties you have created in your .h file.
Hope this helps!
There are 2 ways:
1). You need to put one UIButton and on button action event you may save textview value like:
- (IBAction)btnSaveClicked:(UIButton *)sender
{
strTextViewVal = txtTextView.text;
}
or you may save textview value in its delegate like this:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text

OK button behaves differently when mouse-clicked

I have a modal sheet with an NSTextField control, an OK button and a Cancel push button. The OK button is bound to an action method called theSheetOK in my controller class. I also bound NSTextField control to an NSString member named foo in my controller (File's Owner) and I use key-value bindings to read the text value user entered (i.e. model-key path of text field in the bindings inspector is set to foo).
All works fine if the text is entered and user hits the OK button via keyboard. When I trace the value of foo with NSLog in theSheetOK handler I see the value I just typed in the text field.
However when I clicked the OK button with mouse, the value of foo is logged as empty, also as soon as I click the OK button, the text field control grabs the focus and the text I typed appears selected. Any ideas what went wrong?
#interface MyController : NSWindowController {
#private
NSString *foo;
}
#property (copy, readwrite)NSString* foo;
-(IBAction) theSheetOK:(id)sender;
-(IBAction) theSheetCancel:(id)sender;
#end
...
#import "MyController.h"
#implementation MyController
#synthesize foo;
-(IBAction) theSheetOK:(id)sender
{
NSLog(#"theSheetOK");
NSLog(#"foo= %#", foo);
...
NSWindow* theSheet = [self window];
[NSApp endSheet:theSheet returnCode: NSOKButton];
[theSheet orderOut:nil];
Sometimes you need to press enter to "confirm a change" to cocoa bindings. I'm not sure, but it's possible that when you hit enter both the change and button action are performed.
If that's the case, select your NSTextField and mark the option "Continuously Updates Value" so things get synced properly.

Disable/Enable NSButton if NSTextfield is empty or not

I´m newbie with cocoa. I have a button and a textField in my app. I want the button disabled when the textfield is empty and enabled when the user type something.
Any point to start? Any "magic" binding in Interface Builder?
Thanks
[EDITED]
I´ve tried to set the appDelegate as the NSTextfield´s delegate and added this method (myTextfield and myButton are IBOutlets):
- (void)textDidChange:(NSNotification *)aNotification
{
if ([[myTextField stringValue]length]>0) {
[myButton setEnabled: YES];
}
else {
[myButton setEnabled: NO];
}
}
But nothing happens...
I´ve tried to set the appDelegate as the NSTextfield´s delegate and added this method (myTextfield and myButton are IBOutlets):
- (void)textDidChange:(NSNotification *)aNotification
{
if ([[myTextField stringValue]length]>0) {
[myButton setEnabled: YES];
}
else {
[myButton setEnabled: NO];
}
}
That's the hard way, but it should work just fine. Either you haven't hooked up the text field's delegate outlet to this object, you haven't hooked up the myTextField outlet to the text field, or you haven't hooked up the myButton outlet to the button.
The other way would be to give the controller a property exposing the string value, bind the text field's value binding to this stringValue property, and bind the button's enabled binding to the controller's stringValue.length.
You could also give the controller two properties, one having a Boolean value, and set that one up as dependent upon the string property, and bind the button to that. That's a cleaner and possibly more robust solution, though it is more work.
Here's a solution using bindings.
Below I setup a NSTextField that is bound to the file owner's "text" property. "text" is a NSString. I was caught by "Continuously Updates Value". Thinking my solution didn't work but really it wasn't updating as the user typed, and only when the textfield lost focus.
And now setting up bindings on the button, simply set its enabled state to the length of the file owner's text property.
Annd, the working product.
If you use controlTextDidChange instead of textDidChange, you can get rid of the notification stuff and just rely on being the NSTextField's delegate.
Thanks Peter. What I missed (in my hard way version) is this piece of code in the awakeFromNib in the appDelegate:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(textDidChange:) name:NSControlTextDidChangeNotification object:myTextField];
It works perfect. Now I´m trying the easy way, but I´m afraid I´m not still good enough with the bindings.
To bind the property
#property (retain) IBOutlet NSString *aStringValue;
with the textfield´s value, what I have to use in IB for "Bind to:", "Controller Key" and "Model Key Path"?

What's wrong with this Cocoa code?

I'm trying to make a simple Cocoa application using XCode 3.2.3. In interface builder I added NSTextField and NSButton. When I press the button, I want it to clear whatever is in the text field.
I made a new class called AppController.h. This is the contents:
#import <Foundation/Foundation.h>
#interface AppController : NSObject {
IBOutlet id textView;
}
- (IBAction) clearText: sender;
#end
AppController.m looks like this:
#import "AppController.h"
#implementation AppController
- (IBAction) clearText: sender
{
[textView setString: #" "];
}
#end
I connected the button to clearText and the textbox to textView.
The program compiles without error and runs. But when I press the button, nothing happens. Why is that?
Using id for an IBOutlet is a bad practice. Use
IBOutlet NSTextView* textView;
instead.
Please check using the debugger, or putting NSLog(#"foo!"); before [textView setString:#""] to see if the action method is really called.
Another pitfall is that there are NSTextView and NSTextField. These two are different!
The former supports both setString: and setStringValue:, while the latter only supports setStringValue:.
Which object did you use in the interface builder?

Resources