Невозможно редактировать NSTextField в NSPopover, даже если задано редактируемое поведение

У меня есть приложение, открывающее popover с NSTextField. Текстовое поле не редактируется. Поведение для текстового поля установлено на Editable. Я все еще могу вставить и скопировать текст в это поле, но я не могу его редактировать.

Кто-нибудь знает, что может быть неправильным?

Ответ 1

Не уверен, что вам все еще нужен ответ, но могут быть некоторые другие, которые все еще ищут. Я нашел решение на форумах разработчиков Apple. Цитирование оригинального автора:

Основная проблема заключается в том, как работают клавиатурные события. Хотя NSTextField (и все его супервизоры) получает события клавиатуры, он не предпринимает никаких действий. Это происходит потому, что представление, в котором находится popover, находится в окне, которое не может стать ключевым окном. Вы никак не можете получить доступ к этому окну, по крайней мере, я не мог. Таким образом, решение переопределяет метод canBecomeKeyWindow для каждого NSWindow в нашем приложении с использованием категории.

NSWindow+canBecomeKeyWindow.h
@interface NSWindow (canBecomeKeyWindow)

@end

NSWindow+canBecomeKeyWindow.m
@implementation NSWindow (canBecomeKeyWindow)

//This is to fix a bug with 10.7 where an NSPopover with a text field cannot be edited if its parent window won't become key
//The pragma statements disable the corresponding warning for overriding an already-implemented method
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
- (BOOL)canBecomeKeyWindow
{
    return YES;
}
#pragma clang diagnostic pop

@end

Это делает popover полностью релевантным. Если вам нужно другое окно, которое должно отвечать NO на canBecomeKeyWindow, вы всегда можете сделать подкласс.

Ответ 2

Я тоже боролся с этим, пока не понял, что это ошибка.

Однако вместо того, чтобы полагаться на состояние isActive представления NSStatusItem, я считаю гораздо более надежным использовать свойство isShown реализованного вами NSPopover.

В моем коде у меня есть NSPopover в NSViewController:

  - (BOOL)canBecomeKeyWindow
    {
        if([self class]==NSClassFromString(@"NSStatusBarWindow"))
        {
            NSPopover *mainPopover = [[((AppDelegate*)[NSApp delegate]) mainViewController] mainPopover];
            if(![mainPopover isShown])
                return NO;
        }

        return YES;
    }

Ответ 3

Ответ Balazs Toth работает, но если вы прикрепляете popover к NSStatusItem.view, элемент состояния становится невосприимчивым - требуется два щелчка для фокусировки.

Ответ 4

То, что я нашел при работе с этим решением, заключается в том, что когда NSStatusItem перестает отвечать на запросы, вы можете легко переопределить это поведение, как это

- (BOOL)canBecomeKeyWindow {
    if([self class]==NSClassFromString(@"NSStatusBarWindow")) {
        CBStatusBarView* view = [((CBAppDelegate*)[NSApp delegate]) statusItemView];
        if(![view isActive]) return NO;
    }
    return YES;
}

Вы проверите класс окна, если он соответствует NSStatusBarWindow, мы можем как-то проверить, активен ли NSStatusItem. Если это так, это значит, что мы должны вернуть ДА, потому что этот способ NSPopover из NSStatusItem будет иметь все события клавиатуры.

То, что я использую для проверки того, было ли нажато NSStatusItem нажато (или активно), - это то, что в моем собственном представлении у меня есть значение bool, которое изменяется, когда пользователь нажимает на NSStatusItem система автоматически проверяет "canBecomeKeyWindow", и когда она это сделает, она вернет NO и после того, как пользователь нажмет на нее (пока он возвращает NO), он изменит значение bool и вернет YES, когда система снова запросит (когда NSPopover нажимается для редактирования NSTextField).

Sidenotes

  • CBStatusBarView - это мое пользовательское представление для NSStatusItem
  • CBAppDelegate - класс моего делегата класса

Ответ 5

Если кто-то все еще ищет ответ на этот вопрос, я работаю в Swift.

В то время, когда вы хотите, чтобы поле разрешало ввод текста, я использовал myTextField.becomeFirstReponder()

Чтобы отказаться; просто используйте myTextField.resignFirstResponder()

Ответ 6

Определенно ошибка. Этот отчет об ошибках - это именно то, что я пытался сделать. Даже до создания элемента статуса и переопределения mousdown.

Я могу подтвердить, что ответ Балаза Тота работает. Я просто задаюсь вопросом, может ли это быть в пути по дороге.

Ответ 7

Если кто-то это получит, и вышеприведенное решение не сделает этого. Проблема в моем приложении была на вкладке " info " в targets к которым было применено мое приложение.

Application is background only = true

и был

 Application is agent = true

Провел целый день на этой штуке.

enter image description here