【问题标题】:selectText of NSTextField on focusNSTextField 的 selectText 聚焦
【发布时间】:2010-02-03 21:45:27
【问题描述】:

有人可以建议一种方法来在用户单击 NSTextField 时选择它的所有文本吗?

我确实找到了将NSTextField 子类化的建议,然后使用mouseDownfirstResponder,但目前这超出了我的技能范围。所以我希望有一个更简单的解决方案,或者有人可能会详细说明所需的步骤。

【问题讨论】:

    标签: cocoa select focus nstextfield


    【解决方案1】:

    没有更简单的解决方案,您需要继承 NSTextField 来做您想做的事。如果您要在 Cocoa 中做任何有用的事情,您将需要学习如何处理子类化。

    文本字段的子类化可能相对复杂,因为NSTextField 使用称为字段编辑器的单独NSTextView 对象来处理实际编辑。此文本视图由 NSTextFieldNSWindow 对象返回,并重新用于页面上的所有文本字段。

    像任何NSResponder 子类一样,NSTextField 响应方法-acceptsFirstResponder-becomeFirstResponder。当窗口想要将焦点赋予特定控件或视图时调用这些函数。如果您从这两种方法中返回YES,那么您的控件/视图将具有第一响应者状态,这意味着它是活动控件。但是,如前所述,NSTextField 实际上会在单击时为字段编辑器提供第一响应者状态,因此您需要在 NSTextField 子类中执行以下操作:

    @implementation MCTextField
    - (BOOL)becomeFirstResponder
    {
        BOOL result = [super becomeFirstResponder];
        if(result)
            [self performSelector:@selector(selectText:) withObject:self afterDelay:0];
        return result;
    }
    @end
    

    这首先调用-becomeFirstResponder 的超类实现,它将完成管理字段编辑器的艰苦工作。然后它调用-selectText: 选择字段中的所有文本,但它会在延迟 0 秒后执行此操作,这将延迟到下一次运行事件循环。这意味着将在字段编辑器完全配置后进行选择。

    【讨论】:

    • 非常感谢,它工作得很好,让我学到了一些东西。我根据您提供的代码创建了 .m 文件,.h 文件如下所示:#import @interface MCTextField : NSTextField {} @end 在 Interface Builder 中,我转到 File -> Read Class文件,选择 MCTextField.h,然后我将文本字段的类更改为 MCTextField。
    • 这也是许多通用“以编程方式选择文本”的解决方案 - 例如,NSTextView 中的文本选择例程如果在很多情况下直接调用都不会正确触发,你需要将它们放在 performSelector:afterDelay:0 调用中。叹息
    • 这在 10.9 SDK 中似乎无法正常工作。当我点击该字段时,我会看到一个闪烁的插入符号,除非我设置了很长的延迟,比如 1 秒。
    • 正如@DanielWabyick 所指出的,此解决方案不再有效。我刚刚发布了一个似乎确实适用于 OS X 10.10 的新答案。这个陈旧的答案可能应该被删除。
    • 我很好奇为什么以下所有方法都不起作用。 [自我选择文本:自我]; [self performSelector:@selector(selectText:) withObject:self]; [self performSelectorOnMainThread:@selector(selectText:) withObject:self waitUntilDone:NO];但只有“[self performSelector:@selector(selectText:) withObject:self afterDelay:0];”工作。但是你解释了原因!非常感谢你!我好像找到了一些宝藏。!
    【解决方案2】:

    @Rob 的答案可能在某一时刻有效,但正如@Daniel 指出的那样,它不再有效。看起来 Cocoa 想要跟踪鼠标并拖出一个选择以响应单击,而尝试选择文本以响应 becomeFirstResponder 并不能很好地配合它。

    需要拦截鼠标事件,以防止跟踪。或多或少通过反复试验,我找到了一个似乎适用于 OS X 10.10 的解决方案:

    @interface MyAutoselectTextField : NSTextField
    @end
    
    @implementation MyAutoselectTextField
    - (void)mouseDown:(NSEvent *)theEvent
    {
        [[self currentEditor] selectAll:nil];
    }
    @end
    

    据我所知,当mouseDown: 被调用时,字段编辑器已经设置好了,可能是becomeFirstResponder 的副作用。调用selectAll: 然后选择字段编辑器的内容。在self 上调用selectText: 反而效果不佳,大概是因为设置了字段编辑器。请注意,这里对mouseDown: 的覆盖不会 调用supersuper 会运行一个跟踪循环,拖出一个选择,我们不希望这种行为。请注意,一旦文本字段成为第一响应者,此 mouseDown: 覆盖不会影响选择,因为此时将调用字段编辑器的 mouseDown:

    我不知道这适用于哪些 OS X 版本;如果你在乎,你需要测试它。不幸的是,使用NSTextField 总是有点脆弱,因为字段编辑器的工作方式非常奇怪,并且非常依赖于super 中的实现细节。

    【讨论】:

      【解决方案3】:

      Swift 的一些更新:

      import Cocoa
      
      class TextFieldSubclass: NSTextField {
          override func mouseDown(theEvent: NSEvent) {
              super.mouseDown(theEvent)
              if let textEditor = currentEditor() {
                  textEditor.selectAll(self)
              }
          }
      }
      

      或者为了精确选择:

      import Cocoa
      
      class TextFieldSubclass: NSTextField {
          override func mouseDown(theEvent: NSEvent) {
              super.mouseDown(theEvent)
              if let textEditor = currentEditor() {
                  textEditor.selectedRange = NSMakeRange(location, length)
              }
          }
      }
      

      Swift 版本,适合我:

      import Cocoa
      
      class TextFieldSubclass: NSTextField {
          override func becomeFirstResponder() -> Bool {
              let source = CGEventSourceCreate(CGEventSourceStateID.HIDSystemState)
              let tapLocation = CGEventTapLocation.CGHIDEventTap
              let cmdA = CGEventCreateKeyboardEvent(source, 0x00, true)
              CGEventSetFlags(cmdA, CGEventFlags.MaskCommand)
              CGEventPost(tapLocation, cmdA)
              return true
          }
      }
      

      【讨论】:

        【解决方案4】:

        我喜欢 Konstantin 的解决方案,但它会在每次按下鼠标时都进行选择。这是我用来在mouseDown 方法中选择的一个变体,但前提是它刚刚成为第一响应者:

        class SelectingTextField: NSTextField {
        
            var wantsSelectAll = false
        
            override func becomeFirstResponder() -> Bool {
                wantsSelectAll = true
        
                return super.becomeFirstResponder()
            }
        
            override func mouseDown(with event: NSEvent) {
                super.mouseDown(with: event)
        
                if wantsSelectAll {
                    selectText(self)
                    wantsSelectAll = false
                }
            }
        }
        

        【讨论】:

        • 你可以使用 isHighlighted 来检查
        【解决方案5】:

        我知道这是一个老问题,但这里有一个更新,供那些可能会遇到这个问题的人使用。

        重写 NSTextField 并挂接到 becomeFirstResponder()。您不必担心管理委托或点击。棘手的部分是先找到焦点文本字段的字段编辑器,然后再要求它选择所有文本。

        Objective-C

        // in AutoselectOnFocusTextField.h
        @interface AutoselectOnFocusTextField : NSTextField
        @end
        
        // in AutoselectOnFocusTextField.m
        @implementation AutoselectOnFocusTextField
        - (BOOL)becomeFirstResponder {
            if (![super becomeFirstResponder]) {
                return NO;
            }
            NSText* fieldEditor = [self currentEditor];
            if (fieldEditor != nil) {
                [fieldEditor performSelector:@selector(selectAll:) withObject:self afterDelay:0.0];
            }
            return YES;
        }
        @end
        

        斯威夫特

        class AutoselectOnFocusTextField: NSTextField {
            override func becomeFirstResponder() -> Bool {
                guard super.becomeFirstResponder() else {
                    return false
                }
                if let editor = self.currentEditor() {
                    editor.perform(#selector(selectAll(_:)), with: self, afterDelay: 0)
                }
                return true
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-11-05
          • 1970-01-01
          相关资源
          最近更新 更多