插入和编辑新对象后,当启用NSArrayController“自动重新排列内容”时,键盘焦点丢失

时间:2014-08-14 14:46:49

标签: cocoa interface-builder nstableview nsarraycontroller nsresponder

我只有一个主要细节的应用程序OS X 10.9:
窗口左侧是NSTableView,右侧是NSTextFields的详细信息 我没有专门设置标签顺序,开箱即可正常工作。

插入新对象后除外:

  • 插入新对象后,在NSTableView中选择对象。
  • 点击标签
  • 选择了第一个NSTextField
  • 写点什么,点击标签
  • 现在而不是选择下一个NSTextField 没有 被选中,
  • 点击标签
  • 选择了NSTableView
  • 点击标签
  • 选择了第一个NSTextField

我想要的是什么:

  • 插入新对象后,应选择详细信息部分的第一个NSTextField
  • 点击标签
  • 应选择详细信息部分的下一个NSTextField
  • ...

更新: 我发现奇怪的行为是通过在Interface Builder中启用NSArrayController的“自动重新排列内容”来触发的。如果我禁用它,我不再失去焦点。请参阅CoreData-bound NSTableView loses input focus when items change, but only if sorted

但是,当然,我仍然希望我的内容能够自动进行分类 - 在此操作过程中不会失去我的注意力。可以这样做吗?

UPDATE2:当我的文本字段失去键盘焦点时,我跟着@KenThomases建议并记录了堆栈跟踪:

2014-08-17 16:30:26.003 ResponderExperiment[712:303] (
    0   ResponderExperiment                 0x00000001000014dd -[WMWindow makeFirstResponder:] + 61
    1   AppKit                              0x00007fff8d25c778 -[NSTextView(NSPrivate) _giveUpFirstResponder:] + 257
    2   AppKit                              0x00007fff8d25c56c -[NSTextView(NSKeyBindingCommands) insertTab:] + 270
    3   AppKit                              0x00007fff8d22dc2f -[NSResponder doCommandBySelector:] + 71
    4   AppKit                              0x00007fff8d25b10a -[NSTextView doCommandBySelector:] + 196
    5   AppKit                              0x00007fff8d22d151 -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:] + 1392
    6   AppKit                              0x00007fff8d24c1c2 -[NSTextInputContext handleEvent:] + 845
    7   AppKit                              0x00007fff8d22b9dd -[NSView interpretKeyEvents:] + 180
    8   AppKit                              0x00007fff8d24bd6d -[NSTextView keyDown:] + 658
    9   AppKit                              0x00007fff8d1f856b -[NSWindow sendEvent:] + 1843
    10  AppKit                              0x00007fff8d199b32 -[NSApplication sendEvent:] + 3395
    11  AppKit                              0x00007fff8cfe99f9 -[NSApplication run] + 646
    12  AppKit                              0x00007fff8cfd4783 NSApplicationMain + 940
    13  ResponderExperiment                 0x0000000100002de2 main + 34
    14  libdyld.dylib                       0x00007fff8c5bf5fd start + 1
    15  ???                                 0x0000000000000003 0x0 + 3
)
2014-08-17 16:30:26.014 ResponderExperiment[712:303] (
    0   ResponderExperiment                 0x00000001000014dd -[WMWindow makeFirstResponder:] + 61
    1   AppKit                              0x00007fff8d03c918 -[NSControl abortEditing] + 83
    2   AppKit                              0x00007fff8d2723e0 -[NSValueBinder discardEditing] + 162
    3   AppKit                              0x00007fff8d1aee30 -[NSController discardEditing] + 115
    4   AppKit                              0x00007fff8d1af971 -[NSArrayController rearrangeObjects] + 27
    5   AppKit                              0x00007fff8d3697a9 -[NSArrayController observeValueForKeyPath:ofObject:change:context:] + 294
    6   AppKit                              0x00007fff8d39ac08 -[NSArrayController _setMultipleValue:forKeyPath:atIndex:] + 323
    7   AppKit                              0x00007fff8d39ba12 -[NSArrayController _setSingleValue:forKeyPath:] + 137
    8   Foundation                          0x00007fff8bf9e19a -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] + 285
    9   AppKit                              0x00007fff8d25444c -[NSBinder _setValue:forKeyPath:ofObject:mode:validateImmediately:raisesForNotApplicableKeys:error:] + 364
    10  AppKit                              0x00007fff8d254287 -[NSBinder setValue:forBinding:error:] + 245
    11  AppKit                              0x00007fff8d74c4ee -[NSValueBinder _applyObjectValue:forBinding:canRecoverFromErrors:handleErrors:typeOfAlert:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:] + 194
    12  AppKit                              0x00007fff8d74c871 -[NSValueBinder applyDisplayedValueHandleErrors:typeOfAlert:canRecoverFromErrors:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:error:] + 621
    13  AppKit                              0x00007fff8d74c9d4 -[NSValueBinder _applyDisplayedValueIfHasUncommittedChangesWithHandleErrors:typeOfAlert:discardEditingCallback:otherCallback:callbackContextInfo:didRunAlert:error:] + 127
    14  AppKit                              0x00007fff8d253c2e -[NSValueBinder validateAndCommitValueInEditor:editingIsEnding:errorUserInterfaceHandled:] + 436
    15  AppKit                              0x00007fff8d253a57 -[_NSBindingAdaptor _validateAndCommitValueInEditor:editingIsEnding:errorUserInterfaceHandled:bindingAdaptor:] + 160
    16  AppKit                              0x00007fff8d25399d -[_NSBindingAdaptor validateAndCommitValueInEditor:editingIsEnding:errorUserInterfaceHandled:] + 260
    17  AppKit                              0x00007fff8d25e0ba -[NSTextField textShouldEndEditing:] + 402
    18  AppKit                              0x00007fff8d25dc63 -[NSTextView(NSSharing) resignFirstResponder] + 393
    19  AppKit                              0x00007fff8d136170 -[NSWindow makeFirstResponder:] + 455
    20  ResponderExperiment                 0x000000010000154c -[WMWindow makeFirstResponder:] + 172
    21  AppKit                              0x00007fff8d25c778 -[NSTextView(NSPrivate) _giveUpFirstResponder:] + 257
    22  AppKit                              0x00007fff8d25c56c -[NSTextView(NSKeyBindingCommands) insertTab:] + 270
    23  AppKit                              0x00007fff8d22dc2f -[NSResponder doCommandBySelector:] + 71
    24  AppKit                              0x00007fff8d25b10a -[NSTextView doCommandBySelector:] + 196
    25  AppKit                              0x00007fff8d22d151 -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:] + 1392
    26  AppKit                              0x00007fff8d24c1c2 -[NSTextInputContext handleEvent:] + 845
    27  AppKit                              0x00007fff8d22b9dd -[NSView interpretKeyEvents:] + 180
    28  AppKit                              0x00007fff8d24bd6d -[NSTextView keyDown:] + 658
    29  AppKit                              0x00007fff8d1f856b -[NSWindow sendEvent:] + 1843
    30  AppKit                              0x00007fff8d199b32 -[NSApplication sendEvent:] + 3395
    31  AppKit                              0x00007fff8cfe99f9 -[NSApplication run] + 646
    32  AppKit                              0x00007fff8cfd4783 NSApplicationMain + 940
    33  ResponderExperiment                 0x0000000100002de2 main + 34
    34  libdyld.dylib                       0x00007fff8c5bf5fd start + 1
    35  ???                                 0x0000000000000003 0x0 + 3
)

那么也许我可以编写自己的NSArrayController rearrangeObjects:方法,它不会失去焦点?

2 个答案:

答案 0 :(得分:2)

这是一个可能的解决方案。我们的想法是将文本字段(或更准确地说,为文本字段提供服务的字段编辑器)的响应重新实现为Tab键,作为两个单独的步骤。首先,结束编辑,这将使阵列控制器重新排列其内容。我们通过重置焦点来结束编辑,所以我们不关心阵列控制器可能会做什么来集中注意力。然后,我们自己从最初聚焦的文本字段推进焦点。

在文本字段上设置委托。在该代理中,实现以下方法:

- (BOOL) control:(NSControl*)control textView:(NSTextView*)textView doCommandBySelector:(SEL)command
{
    if (command == @selector(insertTab:))
    {
        // End editing. This will commit the edited value and cause the array controller
        // to rearranged its contents.
        [control.window makeFirstResponder:nil];

        // This will put focus on the next control from the text field.
        [control.window selectKeyViewFollowingView:control];

        // Prevent the normal processing of this command
        return YES;
    }

    if (command == @selector(insertBacktab:))
    {
        // End editing. This will commit the edited value and cause the array controller
        // to rearranged its contents.
        [control.window makeFirstResponder:nil];

        // This will put focus on the previous control from the text field.
        [control.window selectKeyViewPrecedingView:control];

        // Prevent the normal processing of this command
        return YES;
    }

    return NO;
}

我不确定的一件事:如果不是选择远离文本字段,而是单击另一个文本字段,会发生什么。在这种情况下阵列控制器是否仍然重置焦点?

答案 1 :(得分:0)

就我而言,我已经用我自己的逻辑覆盖了NSControl的abortEditing方法。

- (BOOL)abortEditing {
    MyObject *object = [myArrayController.arrangedObjects objectAtIndex:self.editedRow];
    return ![[Manager sharedInstance] isObjectBeingEditing:object];
}