Как определить, когда NSTextField имеет фокус или его содержимое выбрано какао
У меня есть NSTextField внутри NSTableCellView, и я хочу событие, которое информирует меня, когда мой NSTextField получил фокус для отключения нескольких кнопок, я нашел этот метод:
-(void)controlTextDidBeginEditing:(NSNotification *)obj{
NSTextField *textField = (NSTextField *)[obj object];
if (textField != _nombreDelPaqueteTextField) {
[_nuevaCuentaActivoButton setEnabled:FALSE];
[_nuevaCuentaPasivoButton setEnabled:FALSE];
[_nuevaCuentaIngresosButton setEnabled:FALSE];
[_nuevaCuentaEgresosButton setEnabled:FALSE];
}
}
но это срабатывает только тогда, когда мое текстовое поле начинает редактировать, как это говорит, я хочу отключить кнопки, когда я получаю фокус на textField, а не когда я уже начал печатать
РЕДАКТИРОВАТЬ: собираюсь поставить мой код на основе помощи, полученной Джошуа Ноцци, он все еще не работает
MyNSTextField.h
#import <Cocoa/Cocoa.h>
@class MyNSTextField;
@protocol MyNSTextFieldDelegate
@optional -(BOOL)textFieldDidResignFirstResponder:(NSTextField *)sender;
@optional -(BOOL)textFieldDidBecomeFirstResponder:(NSTextField *)sender;
@end
@interface MyNSTextField : NSTextField
@property (strong, nonatomic) id <MyNSTextFieldDelegate> cellView;
@end
MyNSTextField.m
#import "MyNSTextField.h"
@implementation MyNSTextField
- (BOOL)becomeFirstResponder
{
BOOL status = [super becomeFirstResponder];
if (status)
[self.cellView textFieldDidBecomeFirstResponder:self];
return status;
}
- (BOOL)resignFirstResponder
{
BOOL status = [super resignFirstResponder];
if (status)
[self.cellView textFieldDidResignFirstResponder:self];
return status;
}
@end
на моем viewcontroller EdicionDeCuentasWC.m
#import "MyNSTextField.h"
@interface EdicionDeCuentasWC ()<NSTableViewDataSource, NSTableViewDelegate, NSControlTextEditingDelegate, NSPopoverDelegate, MyNSTextFieldDelegate>
@end
@implementation EdicionDeCuentasWC
#pragma mark MyNSTextFieldDelegate
-(BOOL)textFieldDidBecomeFirstResponder:(NSTextField *)sender{
NSLog(@"textFieldDidBecomeFirstResponder");
return TRUE;
}
-(BOOL)textFieldDidResignFirstResponder:(NSTextField *)sender{
NSLog(@"textFieldDidResignFirstResponder");
return TRUE;
}
#pragma mark --
@end
важно сказать, что в визуальном редакторе все мои NSTextFields уже изменены на класс MyNSTextField и назначены делегаты для владельца моего файла (EdicionDeCuentasWC)
4 ответа
Я думаю, что прибил это. Я пытался создать подкласс NSTextFiled
переопределить becomeFirstResponder()
а также resignFirstResponder()
, но как только я нажму на него, becomeFirstResponder()
вызывается и resignFirstResponder()
сразу после этого А? Но поле поиска выглядит так, как будто оно все еще находится в процессе редактирования, и все еще на нем.
Я понял, что когда вы нажимаете на поле поиска, поле поиска становится первым респондентом, но NSText
будет подготовлено где-то позже, и фокус будет перенесен на NSText
,
Я узнал, что когда NSText
подготовлено, установлено self.currentEditor()
, Проблема в том, что когда becomeFirstResponder()
зовем, self.currentEditor()
еще не установил. Так becomeFirstResponder()
это не метод, чтобы обнаружить его фокус.
С другой стороны, когда фокус перемещается на NSText
текстовое поле resignFirstResponder()
называется, а ты знаешь что? self.currentEditor()
установил. Итак, сейчас настало время сообщить своему делегату, что это текстовое поле сфокусировано.
Затем, как определить, когда поле поиска потеряло фокус. Опять же, это о NSText
, Тогда вам нужно слушать NSText
методы делегата, такие как textDidEndEditing()
и убедитесь, что вы позволили суперклассу обработать метод и посмотреть, self.currentEditor()
аннулирован Если это так, NSText
потерял фокус и расскажет об этом делегату текстового поля.
Я даю код, на самом деле NSSearchField
подкласс, чтобы сделать то же самое. И тот же принцип должен работать для NSTextField
также.
protocol ZSearchFieldDelegate: NSTextFieldDelegate {
func searchFieldDidBecomeFirstResponder(textField: ZSearchField)
func searchFieldDidResignFirstResponder(textField: ZSearchField)
}
class ZSearchField: NSSearchField, NSTextDelegate {
var expectingCurrentEditor: Bool = false
// When you clicked on serach field, it will get becomeFirstResponder(),
// and preparing NSText and focus will be taken by the NSText.
// Problem is that self.currentEditor() hasn't been ready yet here.
// So we have to wait resignFirstResponder() to get call and make sure
// self.currentEditor() is ready.
override func becomeFirstResponder() -> Bool {
let status = super.becomeFirstResponder()
if let _ = self.delegate as? ZSearchFieldDelegate where status == true {
expectingCurrentEditor = true
}
return status
}
// It is pretty strange to detect search field get focused in resignFirstResponder()
// method. But otherwise, it is hard to tell if self.currentEditor() is available.
// Once self.currentEditor() is there, that means the focus is moved from
// serach feild to NSText. So, tell it's delegate that the search field got focused.
override func resignFirstResponder() -> Bool {
let status = super.resignFirstResponder()
if let delegate = self.delegate as? ZSearchFieldDelegate where status == true {
if let _ = self.currentEditor() where expectingCurrentEditor {
delegate.searchFieldDidBecomeFirstResponder(self)
// currentEditor.delegate = self
}
}
self.expectingCurrentEditor = false
return status
}
// This method detect whether NSText lost it's focus or not. Make sure
// self.currentEditor() is nil, then that means the search field lost its focus,
// and tell it's delegate that the search field lost its focus.
override func textDidEndEditing(notification: NSNotification) {
super.textDidEndEditing(notification)
if let delegate = self.delegate as? ZSearchFieldDelegate {
if self.currentEditor() == nil {
delegate.searchFieldDidResignFirstResponder(self)
}
}
}
}
Вам нужно будет изменить NSSerachField
в ZSearchField
и ваш класс клиента должен соответствовать ZSearchFieldDelegate
не NSTextFieldDelegate
, Вот пример. Когда пользователь нажимает на поле поиска, оно расширяет его ширину, а когда вы нажимаете на другое место, поле поиска теряет фокус и уменьшает ширину, изменяя значение NSLayoutConstraint
устанавливается Интерфейсным Разработчиком.
class MyViewController: NSViewController, ZSearchFieldDelegate {
// [snip]
@IBOutlet weak var searchFieldWidthConstraint: NSLayoutConstraint!
func searchFieldDidBecomeFirstResponder(textField: ZSearchField) {
self.searchFieldWidthConstraint.constant = 300
self.view.layoutSubtreeIfNeeded()
}
func searchFieldDidResignFirstResponder(textField: ZSearchField) {
self.searchFieldWidthConstraint.constant = 100
self.view.layoutSubtreeIfNeeded()
}
}
Это может зависеть от поведения ОС, я пробовал на El Capitan 10.11.4, и это сработало.
Код также можно скопировать из Gist. https://gist.github.com/codelynx/aa7a41f5fd8069a3cfa2
У меня есть обычай NSTextField
подкласс, который переопределяет -becomeFirstResponder
а также -resignFirstResponder
, это -cellView
свойство требует соответствия протоколу, который объявляет -textDidBecome/ResignFirstResponder:(NSTextField *)sender
но этого достаточно, чтобы дать вам общее представление. Его можно легко изменить, чтобы публиковать уведомления, для которых ваш контроллер может зарегистрироваться в качестве наблюдателя. Надеюсь, это поможет.
- (BOOL)becomeFirstResponder
{
BOOL status = [super becomeFirstResponder];
if (status)
[self.cellView textFieldDidBecomeFirstResponder:self];
return status;
}
- (BOOL)resignFirstResponder
{
BOOL status = [super resignFirstResponder];
if (status)
[self.cellView textFieldDidResignFirstResponder:self];
return status;
}
Я нашел следующий код на форумах macrumors.
- Является ли первый респондент текстовым представлением (редактор полей является текстовым представлением).
- Существует ли редактор полей?
- Является ли текстовое поле делегатом редактора полей?
Вроде работает.
- (BOOL)isTextFieldInFocus:(NSTextField *)textField
{
BOOL inFocus = NO;
inFocus = ([[[textField window] firstResponder] isKindOfClass:[NSTextView class]]
&& [[textField window] fieldEditor:NO forObject:nil]!=nil
&& [textField isEqualTo:(id)[(NSTextView *)[[textField window] firstResponder]delegate]]);
return inFocus;
}
На всякий случай, как небольшую вариацию идеи @sam, мы можем наблюдать NSWindow.firstResponder
Само свойство, по документации KVO-совместимо. Затем сравните это сtextField
или textField.currentEditor()
чтобы выяснить, сфокусировано ли поле.
Swift3.0
Проверьте, выделен ли текст в NSTextField
if theSearchTextField.currentEditor()?.selectedRange.length == 0{
print("IS SeletedAll")
}else{
print("NOT SeletedAll")
}