Question

I want to add the ability to use a date picker when editing a particular column in my table view, and used the code snippet from here, which worked well. However NSDatePicker is not appropriate for my needs so I am using my own custom view, created using IB and loaded via a NSViewController subclass to edit the date.

However I cannot figure out how to dismiss the pop-up menu in a way that accepts the edit, i.e. returns YES in userAcceptedEdit:

BOOL userAcceptedEdit = [menu popUpMenuPositioningItem:nil
                                            atLocation:frame.origin
                                                inView:tableView];

This was working fine when NSDatePicker was the menu's view, but not with my custom view.

I am trapping the enter key actions from the text fields in my custom view, but all I can figure out is how to cancel the menu tracking which makes userAcceptedEdit == NO:

MyCustomViewController.mm:

- (IBAction)textFieldAction:(id)sender {
    logdbg(@"Action");
    NSMenu* menu = [[self.view enclosingMenuItem] menu];
    [menu cancelTracking];
}

The Views in Menu Items section of Apple's Application Menu and Pop-up List Programming Topics doesn't cover it either...

EDIT Here is a sample project, that demonstrates the issue.

Can someone provide some guidance please?

Was it helpful?

Solution

You should also be able to set the textFields' delegate to the NSViewController, implement NSTextFieldDelegate within the ViewController and do something like this

- (void)controlTextDidEndEditing:(NSNotification *)aNotification{
    // NSTextField * textField = [aNotification object];
    NSUInteger whyEnd = [[[aNotification userInfo] objectForKey:@"NSTextMovement"] unsignedIntValue];
    if(whyEnd == NSReturnTextMovement){
        // Create new event here using the below routine

        /*
        [[self window] keyDown: [NSEvent keyEventWithType:(NSEventType)type 
                                                 location:(NSPoint)location 
                                            modifierFlags:(NSUInteger)flags 
                                                timestamp:(NSTimeInterval)time 
                                             windowNumber:(NSInteger)windowNum 
                                                  context:(NSGraphicsContext *)context 
                                               characters:(NSString *)characters 
                              charactersIgnoringModifiers:(NSString *)unmodCharacters 
                                                isARepeat:(BOOL)repeatKey
                                                  keyCode:(unsigned short)code]
         ];
         */ 
    }
 }

Here you are essentially TRANSLATING the notification to an EVENT by creating a NEW event to pass along to the parent view

Should also be noted that this becomes the central "dispatch" return catcher for all textfields.

Here is a great link on using the NSEvent creation methods: http://advinprog.blogspot.com/2008/06/so-you-want-to-post-keyboard-event-in.html

Notice in this writeup how the simulate a key_down and a key_up!!!

OTHER TIPS

Ha! Did it. Changed the NSTextField to NSTextView, subclassed it, and here we go:

@interface LNTextView : NSTextView

@end

@implementation LNTextView

- (void)keyDown:(NSEvent *)theEvent
{
    if(theEvent.keyCode == 36)
    {
        [[self window] keyDown:theEvent];
    }
}

@end

I noticed that, normally, when enter key is pressed on NSDatePicker, the keyDown: eventually goes to the menu's window and then it is accepted. So this is what I did here. NSTextField uses a text view internally, so it cannot hear keyDown: messages, thus the need to switch to full blown NSTextView instead.

You could still use your text field, and create a new NSEvent using + (NSEvent *)keyEventWithType:(NSEventType)type location:(NSPoint)location modifierFlags:(NSUInteger)flags timestamp:(NSTimeInterval)time windowNumber:(NSInteger)windowNum context:(NSGraphicsContext *)context characters:(NSString *)characters charactersIgnoringModifiers:(NSString *)unmodCharacters isARepeat:(BOOL)repeatKey keyCode:(unsigned short)code in your action method, passing it to the field's window instead of calling cancelTracking on the menu.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top