【问题标题】:NSTextField controlTextDidEndEditing: called while being edited (inside an NSOutlineView)NSTextField controlTextDidEndEditing:在编辑时调用(在 NSOutlineView 内)
【发布时间】:2014-04-12 21:36:12
【问题描述】:

在我的 NSOutlineView 中,我在 NSTableCellView 中有一个 NSTextField。我正在监听 controlTextDidEndEditing: 用户完成编辑时发生的通知。但是,在我的情况下,即使用户正在打字,甚至在打字时暂停一秒钟,这个通知也会被触发。这似乎很奇怪。我在同一个视图中测试了一个 NSTextField,但在 NSOutlineView 之外,它的行为不是这样的;它只调用 controlTextDidEndEditing: 如果用户按下 Tab 或 Enter 键(如预期的那样)。

我可以做些什么来阻止 NSTextField 发送 controlTextDidEndEditing: 除非按下 Enter 或 Tab 键?

【问题讨论】:

    标签: cocoa uitextfield nstableview nstextfield nsoutlineview


    【解决方案1】:

    找到了解决方案:

    - (void)controlTextDidEndEditing:(NSNotification *) notification {
    
        // to prevent NSOutlineView from calling controlTextDidEndEditing by itself
        if ([notification.userInfo[@"NSTextMovement"] unsignedIntegerValue]) {
             ....
    

    【讨论】:

      【解决方案2】:

      这是一个老问题,但作为参考,我遇到了一个类似的问题,在编辑会话开始时调用了controlTextDidEndEditing:

      我的解决方法是检查文本字段是否仍然具有焦点(即光标):

      func controlTextDidEndEditing(_ obj: Notification) {
      
          guard
              let textField = obj.object as? NSTextField,
              !textField.isFocused
          else {
              return
          }
          ...
      }
      
      public extension NSTextField
      {
          public var isFocused:Bool {
              if
                  window?.firstResponder is NSTextView,
                  let fieldEditor = window?.fieldEditor(false, for: nil),
                  let delegate = fieldEditor.delegate as? NSTextField,
                  self == delegate
              {
                  return true
              }
              return false
          }
      }
      

      自我说明:

      我在向NSOutlineView 添加新项目并使用NSOutlineView.editColumn(row:,with:,select) 使其可编辑时遇到了这个问题。

      controlTextDidEndEditing() 将在编辑会话开始时立即调用。

      事实证明这是第一响应者/动画竞争条件。我在插入行时使用了NSTableView.AnimationOptions.slideDown 动画,然后使行可编辑。

      这里的问题是该行在仍处于动画状态时是可编辑的。动画结束后,第一响应者切换到窗口并返回到文本字段,这会导致调用 controlTextDidEndEditing()

      outlineView.beginUpdates()
      outlineView.insertItems(at: IndexSet(integer:atIndex),
                              inParent: intoParent == rootItem ? nil : intoParent,
                              withAnimation: .slideDown) // Animating!
      outlineView.endUpdates()
      
      // Problem: the animation above won't have finished leading to first responder issues.
      self.outlineView.editColumn(0, row: insertedRowIndex, with: nil, select: true)
      

      解决方案 1:

      插入行时不要使用动画。

      解决方案 2:

      beginUpdates/endUpdates 包装到NSAnimationContext 组中,添加一个完成处理程序以仅在动画完成后开始编辑。

      调试提示:

      • 观察窗口控制器中firstResponder 的变化
      • controlTextDidEndEditing() 中放置一个断点,并仔细查看堆栈跟踪,看看是什么导致它被调用。在我的案例中,它泄露的是对动画调用的引用。
      • 要重现,请将 beginUpdates/endUpdates 包裹在 NSAnimationContext 中,并将动画持续时间增加到几秒钟。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-17
        • 1970-01-01
        • 1970-01-01
        • 2011-08-01
        • 1970-01-01
        相关资源
        最近更新 更多