4

我真的很希望我的自定义视图可以与-moveLeft:, -deleteForward:,-selectAll:等一起使用,但我也想将我不关心的任何键传递到响应者链上。现在我要优先-keyDown:调用 call [self interpretKeyEvents:[NSArray arrayWithObject:event]];,但这似乎占用了所有关键事件,即使是我的视图没有响应的事件。

有什么方法可以将不需要的事件向上传递,但仍然响应-moveLeft:等?或者我是否需要实施我自己的所有行动,-keyDown:以便我知道我做了什么,没有回应什么?

4

3 回答 3

5

遇到这个试图找到解决同样问题的方法。从来没有在网上找到任何东西,但我想出了一些到目前为止似乎运作良好的东西。这就是我正在做的事情:

子类化您的 NSTextView (或您正在使用的任何东西)并创建一个实例变量来临时存储 key down event 。. .

@interface MyTextView : NSTextView {
    NSEvent* _keyDownEvent;
}

@end

然后像这样定义视图的方法(如果您使用自动引用计数,请取出保留/释放垃圾):

@implementation MyTextView

- (id)initWithFrame:(NSRect)frame {
    if (self = [super initWithFrame:frame]) {
        _keyDownEvent = nil;
    }

    return self;
}

- (void)keyDown:(NSEvent*)event {
    [_keyDownEvent release];
    _keyDownEvent = [event retain];
    [super keyDown:event];
}

- (void)doCommandBySelector:(SEL)selector {
    if (_keyDownEvent && selector == @selector(noop:)) {
        if ([self nextResponder]) {
            [[self nextResponder] keyDown:[_keyDownEvent autorelease]];
        } else {
            [_keyDownEvent release];
        }
        _keyDownEvent = nil;
    } else {
        [super doCommandBySelector:selector];
    }
}

- (void)dealloc {
    [_keyDownEvent release];

    [super dealloc];
}

@end

这就是我如何做到这一点的。未处理按键时,您会听到哔声。所以,我在 NSBeep() 上设置了一个断点,当程序崩溃时,我在 GDB 中吐出了一个堆栈跟踪:

#0  0x00007fff96eb1c2d in NSBeep ()
#1  0x00007fff96e6d739 in -[NSResponder doCommandBySelector:] ()
#2  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#3  0x00007fff96fda826 in -[NSWindow doCommandBySelector:] ()
#4  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#5  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#6  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#7  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#8  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#9  0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#10 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#11 0x00007fff96f486ce in -[NSTextView doCommandBySelector:] ()
#12 0x00007fff96da1c93 in -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:] ()
#13 0x00007fff970f5382 in -[NSTextInputContext handleEvent:] ()
#14 0x00007fff96fbfd2a in -[NSView interpretKeyEvents:] ()
#15 0x00007fff96f38a25 in -[NSTextView keyDown:] ()
#16 0x0000000100012889 in -[MyTextView keyDown:] (self=0x1004763a0, _cmd=0x7fff972b0234, event=0x100197320) at /path/MyTextView.m:24
#17 0x00007fff96a16b44 in -[NSWindow sendEvent:] ()
#18 0x00007fff969af16d in -[NSApplication sendEvent:] ()
#19 0x00007fff969451f2 in -[NSApplication run] ()
#20 0x00007fff96bc3b88 in NSApplicationMain ()
#21 0x00000001000015e2 in main (argc=3, argv=0x7fff5fbff8f0) at /path/main.m:12

发生的事情是这样的:当按键按下事件不用于文本输入时,“noop”命令被发送到响应链。默认情况下,当它脱离响应链时会触发哔声。在我的解决方案中,NSTextView 子类捕获 noop 命令,而是将原始 keyDown 事件沿响应链向下抛出。然后您的 NSWindow 或其他视图将正常获得任何未使用的 keyDown 事件。

于 2012-03-04T21:08:42.810 回答
3

这是我对@daxnitro 答案的快速实现,并且似乎有效:

import Cocoa

class EditorTextView: NSTextView {

    private var keyDownEvent: NSEvent?

    required init?(coder aCoder: NSCoder) {
        super.init(coder: aCoder)
    }

    override init() {
        super.init()
    }

    override init(frame frameRect: NSRect, textContainer aTextContainer: NSTextContainer!) {
        super.init(frame: frameRect, textContainer: aTextContainer)
    }

    override func keyDown(event: NSEvent) {
        keyDownEvent = event
        super.keyDown(event)
    }

    override func doCommandBySelector(aSelector: Selector) {
        if aSelector != NSSelectorFromString("noop:") {
            super.doCommandBySelector(aSelector)
        } else if  keyDownEvent != nil {
            self.nextResponder?.keyDown(keyDownEvent!)
        }
        keyDownEvent = nil
    }

}
于 2015-01-19T03:06:47.723 回答
0

NSTextView我有一个与NSTableView. 我希望能够NSTextViewNSTableView.

我的解决方案是简单地覆盖responds(to:)NSTextView并决定我是否想在那里处理它。

override func responds(to aSelector: Selector!) -> Bool  {
  if aSelector == #selector(moveUpAndModifySelection(_:)) {
    return selectedRange().location != 0
  }
            
  return super.responds(to: aSelector)
}
于 2020-06-23T11:09:41.963 回答