Как принять редактирование и отклонить всплывающее меню, содержащее пользовательский вид?

Я хочу добавить возможность использования выбора даты при редактировании определенного столбца в моем представлении таблицы и использовать фрагмент кода из здесь, который работал хорошо. Однако NSDatePicker не подходит для моих нужд, поэтому я использую собственное собственное представление, созданное с помощью IB и загружаемое через подкласс NSViewController для редактирования даты.

Однако я не могу понять, как отклонить всплывающее меню таким образом, который принимает редактирование, т.е. возвращает YES в userAcceptedEdit:

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

Это прекрасно работало, когда NSDatePicker был видом меню, но не с моим пользовательским представлением.

Я улавливаю действия клавиш ввода из текстовых полей в своем пользовательском представлении, но все, что я могу выяснить, - это отменить отслеживание меню, которое делает userAcceptedEdit == NO:

MyCustomViewController.mm:

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

Представления в пунктах меню в разделе "Меню приложений Apple" и "Всплывающие списки" не охватывают его также...

EDIT Вот образец проекта, который демонстрирует проблему.

Может ли кто-нибудь дать некоторые рекомендации?

Ответ 1

Вы также должны установить делегат textFields в NSViewController, реализовать NSTextFieldDelegate в ViewController и сделать что-то вроде этого

- (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]
         ];
         */ 
    }
 }

Здесь вы, по сути, ПЕРЕВЕСТИ ИЗОБРЕТЕНИЯ к СОБЫТИЮ, создав новое событие, чтобы перейти к родительскому представлению

Следует также отметить, что это становится центральной утилитой возврата отправки для всех текстовых полей.

Вот отличная ссылка на использование методов создания NSEvent: http://advinprog.blogspot.com/2008/06/so-you-want-to-post-keyboard-event-in.html

Обратите внимание на эту запись, как имитировать key_down и key_up!!!

Ответ 2

Ха! Сделал это. Изменен NSTextField на NSTextView, подклассифицирован он, и вот мы идем:

@interface LNTextView : NSTextView

@end

@implementation LNTextView

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

@end

Я заметил, что обычно, когда клавиша ввода нажата на NSDatePicker, keyDown: в конечном итоге переходит в окно меню, а затем принимается. Так вот что я здесь сделал. NSTextField использует текстовый вид внутри, поэтому он не может слышать сообщения keyDown:, поэтому нужно переключиться на полноэкранный NSTextView.

Вы все равно можете использовать свое текстовое поле и создать новый NSEvent с помощью + (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 в своем методе действий, передав его в окно поля вместо вызова cancelTracking в меню.