本文主要是介绍textfield keydown,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Text Field 与 Field Editor
Cocoa 提供了两种文本编辑控件 [1]:NSTextView
和 NSTextField
。从表面上看,前者比后者功能丰富,前者一般用作复杂的文字编辑,后者一般接受简单的数据输入。二者处理 Enter 和 Tab 键的行为不同。NSTextView
的方式和通常的编辑器相同:给编辑内容添加换行或者 tab 字符。
NSTextField
的方式则类似于其它非文本编辑的 Cocoa 控件:Enter 键触发 target action(缺省为终止编辑),Tab 键令焦点移到相邻的下一控件。
有瑕疵的世界观
如果根据表面现象粗浅地猜测,有这么几种可能:
- 二者是实现完全不同的类,运行时没有协作;
NSTextView
是NSTextField
的子类;NSTextField
是NSTextView
的封装,对外隐藏后者的高级功能。
实际上这三个猜测都是错误的。查看文档可以排除第二种。另外两种的真伪则要花些功夫来辩明。当然,很多应用界面仅需要 NSTextView
提供的缺省 rich-text 编辑功能以及把 NSTextField
作为简短数据输入方式,所以我们大可以采用第一种假设来开发 90% 的应用。但若需要精细调整文本编辑行为,采用有瑕疵的猜想像是用牛顿力学和以太的概念指导宇宙航行。
以太概念的抛弃
要了解两个类的关系,它们的命名可以作为切入点——其中的「field」是什么意思?在数据库记录、表格或文件格式中一段相对独立的数据经常被称为「field」,所以自然的猜想是 NSTextField
作为简单的数据输入方式其名称中的「field」源于此意。但是 field 还有「现场」、「场所」的意思。
其实在 Cocoa 中提供文本编辑功能的类只有 NSTextView
。
NSTextField
不是 NSTextView
的封装,它的作用是为实际承担编辑工作的 NSTextView
提供操作「场所」。其名称中「field」的意义不是表格或文件格式意义上的 field。当一个 NSTextField
控件不拥有焦点的时候,它只显示自己存储的文本值 [2],并不和 NSTextView
有任何关系。当它获得焦点时,其所在的窗口会把一个 NSTextView
控件置于其上,并将原来的 NSTextField
对象设置为该 NSTextView
对象的 delegate,真正获取焦点并且成为 first responder 的控件是 NSTextView
对象。在同一窗口中,置于所有 NSTextField
之上的是同一个 NSTextView
对象实例。因为只有一个控件能获得焦点,所以共享单一的 NSTextView
实例没有问题。这个唯一的实例称为「field editor」,即放置在 text field 上的 editor。
Field editor 由窗口负责创建和管理。开发者如果希望实现自己的 field editor,可以重写 (overried 或者 implement) 下面的函数之一:
NSWindow
的fieldEditor:forObject:
。- 窗口的 delegate 的
windowWillReturnFieldEditor:toObject:
。
在说明 field editor 机制如何导致对 Enter/Tab 的不同处理行为之前,先简单说明一下 Cocoa 对键盘事件的总体处理机制。下图截自《Cocoa Event Handling Guide》,Figure 1-5。
最后一步「Insert as character in view」对于 NSTextView
来说相当于接收到 keyDown:
消息。Enter/Tab 作为 key action 被路径中更早的模块截取 [3],即图中的「Send action message to first responder」。所以 Enter/Tab 事件不会向 field editor 发送 keyDown:
消息,而是分别发送 insertNewLine:
和 insertTab:
消息。
现在回到 NSTextView
和 NSTextField
对 Enter/Tab 的不同处理。严格的说是非 field editor 的 NSTextView
对象和作为 field editor 的 NSTextView
对象的不同行为。 NSTextView
的 isFieldEditor
属性表示当前对象是否为 field editor。一切行为差异的秘密就在于 insertNewLine:
和 insertTab:
会根据 isFieldEditor
的返回值来决定控件的行为。
问题的解决
有了正确的世界观,就可以自由地对文本编辑行为作出调整。比如,如何让控件在接收到 Enter/Tab 事件的时候始终插入相应的字符而非终止编辑或者切换焦点?可以有以下方案:
- 始终用
NSTextView
,并且保证isFieldEditor
属性返回NO
。 - 重写窗口 delegate 的
windowWillReturnFieldEditor:toObject:
,返回 custom field editor。此方案需要创建两个新类:窗口 delegate 和NSTextView
的子类。后者的insertNewLine:
和insertTab:
需要被改写。 - 让处理 key action 的模块发送
insertNewLineIgnoringFieldEditor:
和
insertTabIgnoringFieldEditor:
消息给 field editor,保证始终插入换行或 tab 字符。
下面详细说一下如何实现最后一个方案。处理 key action 的模块首先检查拥有焦点的 NSTextField
是否有 delegate。如果有的话会向其发送 control:textView:doCommandBySelector:
消息。重写此函数可以改变发送到 field editor 的消息 [4] [5]。
- (BOOL)control:(NSControl*)control textView:(NSTextView*)fieldEditordoCommandBySelector:(SEL)commandSelector {if (commandSelector == @selector(insertNewline:)) {[fieldEditor insertNewlineIgnoringFieldEditor:self];return YES;} else if (commandSelector == @selector(insertTab:)) {[fieldEditor insertTabIgnoringFieldEditor:self];return YES;}return NO; }
这篇关于textfield keydown的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!