I cannot find a simple example of how to use an NSTextField to edit it's contents in place.
Exactly like in the Finder - you're able to click, and with a short delay the text field becomes editable.
It seems like it's some combination of the textField, it's cell, and the fieldEditor? Problem is I can't find the most basic example of how to do it.
I've tried subclassing NSTextField with a couple different tests but it hasn't worked:
#import "GWTextField.h"
@implementation GWTextField
- (id) initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
return self;
}
- (void) mouseDown:(NSEvent *)theEvent {
[super mouseDown:theEvent];
[self.cell editWithFrame:self.frame inView:self.superview editor:[self.cell fieldEditorForView:self] delegate:self event:theEvent];
//[self setEditable:TRUE];
//[self setSelectable:TRUE];
//[self selectText:nil];
[NSTimer scheduledTimerWithTimeInterval:.3 target:self selector:@selector(edit:) userInfo:nil repeats:FALSE];
}
- (void) edit:(id) sende {
NSLog(@"edit");
[[NSApplication sharedApplication].mainWindow makeFirstResponder:self];
[self selectText:nil];
}
@end
Any ideas?
Here's another solution with no NSCell - one user pointed out that NSCell is deprecated and will at some point be gone.
#import <Cocoa/Cocoa.h>
@interface EditTextField : NSTextField <NSTextDelegate,NSTextViewDelegate,NSTextFieldDelegate>
@property BOOL isEditing;
@property BOOL commitChangesOnEscapeKey;
@property BOOL editAfterDelay;
@property CGFloat delay;
@end
----
#import "EditTextField.h"
@interface EditTextField ()
@property NSObject <NSTextFieldDelegate,NSTextViewDelegate> * userDelegate;
@property NSString * originalStringValue;
@property NSTimer * editTimer;
@property NSTrackingArea * editTrackingArea;
@end
@implementation EditTextField
- (id) initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
[self defaultInit];
return self;
}
- (id) initWithFrame:(NSRect)frameRect {
self = [super initWithFrame:frameRect];
[self defaultInit];
return self;
}
- (id) init {
self = [super init];
[self defaultInit];
return self;
}
- (void) defaultInit {
self.delay = .8;
}
- (void) mouseDown:(NSEvent *) theEvent {
if(theEvent.clickCount == 2) {
[self startEditing];
} else {
[super mouseDown:theEvent];
if(self.editAfterDelay) {
[self startTracking];
self.editTimer = [NSTimer scheduledTimerWithTimeInterval:.8 target:self selector:@selector(startEditing) userInfo:nil repeats:FALSE];
}
}
}
- (void) startTracking {
if(!self.editTrackingArea) {
self.editTrackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds options:NSTrackingMouseEnteredAndExited|NSTrackingMouseMoved|NSTrackingActiveInActiveApp|NSTrackingAssumeInside|NSTrackingInVisibleRect owner:self userInfo:nil];
}
[self addTrackingArea:self.editTrackingArea];
}
- (void) mouseExited:(NSEvent *)theEvent {
[self.editTimer invalidate];
self.editTimer = nil;
}
- (void) mouseMoved:(NSEvent *) theEvent {
[self.editTimer invalidate];
self.editTimer = nil;
}
- (void) startEditing {
id firstResponder = self.window.firstResponder;
if([firstResponder isKindOfClass:[NSTextView class]]) {
NSTextView * tv = (NSTextView *)firstResponder;
if(tv.delegate && [tv.delegate isKindOfClass:[EditTextField class]]) {
EditTextField * fr = (EditTextField *)tv.delegate;
[fr stopEditingCommitChanges:FALSE clearFirstResponder:FALSE];
}
}
if(self.delegate != self) {
self.userDelegate = (NSObject <NSTextFieldDelegate,NSTextViewDelegate> *)self.delegate;
}
self.isEditing = TRUE;
self.delegate = self;
self.editable = TRUE;
self.originalStringValue = self.stringValue;
[self.window makeFirstResponder:self];
}
- (void) stopEditingCommitChanges:(BOOL) commitChanges clearFirstResponder:(BOOL) clearFirstResponder {
self.editable = FALSE;
self.isEditing = FALSE;
self.delegate = nil;
[self removeTrackingArea:self.editTrackingArea];
if(!commitChanges) {
self.stringValue = self.originalStringValue;
}
if(clearFirstResponder) {
[self.window makeFirstResponder:nil];
}
}
- (void) cancelOperation:(id) sender {
if(self.commitChangesOnEscapeKey) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:TRUE];
} else {
[self stopEditingCommitChanges:FALSE clearFirstResponder:TRUE];
}
}
- (BOOL) textView:(NSTextView *) textView doCommandBySelector:(SEL) commandSelector {
BOOL handlesCommand = FALSE;
NSString * selector = NSStringFromSelector(commandSelector);
if(self.userDelegate) {
if([self.userDelegate respondsToSelector:@selector(control:textView:doCommandBySelector:)]) {
handlesCommand = [self.userDelegate control:self textView:textView doCommandBySelector:commandSelector];
} else if([self.userDelegate respondsToSelector:@selector(textView:doCommandBySelector:)]) {
handlesCommand = [self.userDelegate textView:textView doCommandBySelector:commandSelector];
}
if(!handlesCommand) {
if([selector isEqualToString:@"insertNewline:"]) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:TRUE];
handlesCommand = TRUE;
}
if([selector isEqualToString:@"insertTab:"]) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:FALSE];
handlesCommand = FALSE;
}
}
} else {
if([selector isEqualToString:@"insertNewline:"]) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:TRUE];
handlesCommand = TRUE;
}
if([selector isEqualToString:@"insertTab:"]) {
[self stopEditingCommitChanges:TRUE clearFirstResponder:FALSE];
handlesCommand = FALSE;
}
}
return handlesCommand;
}
@end
In my application I have two text fields - one non editable, and second, hidden, editable, and activates title editing by calling:
[self addSubview:windowTitle];
[windowTitleLabel removeFromSuperview];
[self.window makeFirstResponder:windowTitle];
This is called from mouseUp: on view behind the label.
I don't remember why I needed to have two text fields (i didn't know Cocoa good that time), probably it will work even without label swapping.
I built a re-usable NSTextField subclass you can use for edit in place functionality. http://pastebin.com/QymunMYB
I came up with a better solution to the edit in place problem. I believe this is how to properly do edit in place with NSCell. Please show and tell if this is wrong.
#import <Cocoa/Cocoa.h>
@interface EditTextField : NSTextField <NSTextDelegate>
@end
---
#import "EditTextField.h"
@implementation EditTextField
- (void) mouseDown:(NSEvent *)theEvent {
if(theEvent.clickCount == 2) {
self.editable = TRUE;
NSText * fieldEditor = [self.window fieldEditor:TRUE forObject:self];
[self.cell editWithFrame:self.bounds inView:self editor:fieldEditor delegate:self event:theEvent];
} else {
[super mouseDown:theEvent];
}
}
- (void) cancelOperation:(id)sender {
[self.cell endEditing:nil];
self.editable = FALSE;
}
- (BOOL) textView:(NSTextView *) textView doCommandBySelector:(SEL) commandSelector {
NSString * selector = NSStringFromSelector(commandSelector);
if([selector isEqualToString:@"insertNewline:"]) {
NSText * fieldEditor = [self.window fieldEditor:TRUE forObject:self];
[self.cell endEditing:fieldEditor];
self.editable = FALSE;
return TRUE;
}
return FALSE;
}
@end
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.