Reputation: 9170
I am having trouble making a dynamic unit converter. I have two text fields: one for "inches" and another for "feet". My goal is to convert the inches to feet as the numbers are being entered and vice versa. I want the action to happen dynamically, not when the "Enter" or "Tab" button is pressed.
I am using the NSTextField with Number Formatter. So I need the formatter to also work as the calculation takes place. I have tried the -(void)controlTextDidChange method but the formatter does not work with it.
See below for my current code which does not work dynamically.
#import <Foundation/Foundation.h>
@interface Convert : NSObject {
IBOutlet NSTextField *inches;
IBOutlet NSTextField *feet;
}
- (IBAction)textDidChange:(id)sender;
@end
and
#import "Convert.h"
@implementation Convert
- (IBAction)textDidChange:(id)sender {
if (sender == inches) {
float myInches = [inches floatValue];
[feet setFloatValue: (myInches/12)];
}
else if (sender == feet) {
float myFeet = [feet floatValue];
[inches setFloatValue: (myFeet*12)];
}
}
@end
Can anyone tell me how to accomplish this without having to press the "Enter" or "Tab" key?
...Now trying the NSValueTransformer approach using NSForm instead of NSTextField...
#import <Foundation/Foundation.h>
@interface LengthConverter : NSValueTransformer
+ (Class)transformedValueClass;
+ (BOOL)allowsReverseTransformation;
- (id)transformedValue:(id)value;
- (id)reverseTransformedValue:(id)value;
@end
and
#import "LengthConverter.h"
@implementation LengthConverter
+ (Class)transformedValueClass {
return [NSNumber class];
}
+ (BOOL)allowsReverseTransformation {
return YES;
}
- (id)transformedValue:(id)value {
if (value == nil) return nil;
if (![value respondsToSelector: @selector(doubleValue)]) {
[NSException raise:NSInternalInconsistencyException format:@"Value does not respond",[value class]];
}
CGFloat inchesInputValue = [value doubleValue]; // handles NSString and NSNumber
CGFloat feetOutputValue = inchesInputValue / 12;
return [NSNumber numberWithDouble: feetOutputValue];
}
- (id)reverseTransformedValue:(id)value {
if (value == nil) return nil;
if (![value respondsToSelector: @selector(doubleValue)]) {
[NSException raise:NSInternalInconsistencyException format:@"Value does not respond",[value class]];
}
CGFloat feetInputValue = [value doubleValue]; // handles NSString and NSNumber
CGFloat inchesOutputValue = feetInputValue * 12;
return [NSNumber numberWithDouble: inchesOutputValue];
}
@end
Upvotes: 1
Views: 959
Reputation: 104698
You can bind values using NSValueTransformer
s.
NSValueTransformer
offers object to object transformations, which you can also use in XIBs and bindings. The system defines a few, and you can define your own quite easily. Apple's TemperatureConverter sample would be a good starting point for an introduction to NSValueTransformer
.
Update in response to sample
In + [ApplicationDelegate initialize]
, you'll see the program register all the transformers it needs. They register to a name, such as @"centrigradeFromKelvin"
.
Once the trafos you will need are registered, you can use the transformer in the NIB. In the TemperatureConvertoer example, you can:
Upvotes: 2