4

我正在尝试找到一种解决方案,允许我在视图控制器中获取 keydown 事件。我不相信默认情况下视图控制器是响应者链的一部分。

我将不胜感激如何进行此操作的示例。我很难找到我能理解的关于如何将 VC 添加到响应者链并获取事件的文档。

谢谢。

米克

4

3 回答 3

3

你可以实现这样的事情:

-(void) globalKeyDown: (NSNotification *) notification 

控制器类中的方法,然后只需在控制器的 awakeFromNib 或 loadView 方法中添加观察者

- (void)awakeFromNib
{
    [[NSNotificationCenter defaultCenter] addObserver:self 
                                             selector:@selector(globalKeyDown:)
                                                 name:@"my_keyEvent" 
                                               object:nil];
}

在您的视图类中

-(void)keyDown:(NSEvent *)theEvent
{
    [[NSNotificationCenter defaultCenter] postNotificationName:@"my_keyEvent"
                                                    object:theEvent
                                                  userInfo:@{@"sender":self}];
}
于 2013-11-15T00:30:25.810 回答
2

在您的 NSWidow(或 NSWindowController)类实现中,将您的视图控制器设置为第一响应者:

[self makeFirstResponder:yourViewControllerInstance];

当然,您必须让您的 NSViewController 类对 AcceptsFirstResponder 消息返回 YES。

于 2014-12-29T16:23:15.717 回答
2

NSViewController没有默认的方法来做到这一点。但是,您可以通过子类化来实现这一点NSView。这是基本思想:

  • 如果创建视图子类,则可以将视图控制器设置为委托并创建处理事件的委托方法。
  • 您可以在视图标题的开头声明一个委托协议。
  • 在视图控制器标题中导入您的视图标题。将视图控制器声明为实现协议。
  • 在您看来keyDown,将事件发送给委托人。

另一种方法是在您的视图控制器中发布NSNotificationskeyDown观察和处理通知。其他方式也存在。

NSView 子类与 Delegate 方法解释

这是一个带有子类的委托示例,该NSView子类在其标头中使用一个必需的方法声明协议,IBOutlet即符合协议的 id 属性。子类可以随时调用这个NSView方法给它的委托。如果委托为 nil,那在 Cocoa 中没问题。另请注意,切线地,我已将IB_Designable和添加IBInspectable到视图的颜色属性中。这允许在 IB 中设置它们并且需要 10.10 SDK。

应用程序委托已NSView在实现文件中导入了子类,并在 .m 文件顶部的类扩展中AppDelegate.m采用了协议。AppDelegate在该@implementation部分中,它还实现了该方法。

另请注意,在 IB 中,我NSView在窗口中添加了一个,然后将其类设置为NSView检查器中的自定义子类。最后,我将其设置为 IBeventDelegate IBOutlet中的AppDelegate代理。

自定义 NSView 子类接口

#import <Cocoa/Cocoa.h>


@protocol EventDelegatingViewDelegate <NSObject>

- (void)view:(NSView *)aView didHandleEvent:(NSEvent *)anEvent;

@end

IB_DESIGNABLE
@interface EventDelegatingView : NSView

@property IBOutlet id<EventDelegatingViewDelegate> eventDelegate;
@property IBInspectable NSColor *fillColor;
@property IBInspectable NSColor *strokeColor;

@end

自定义 NSView 子类实现

#import "EventDelegatingView.h"



@implementation EventDelegatingView

- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent {return YES;}

    // The following two methods allow a view to accept key input events. (literally they say, YES, please send me those events if I'm the center of attention.)
- (BOOL)acceptsFirstResponder {return YES;}
- (BOOL)canBecomeKeyView {return YES;}

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];

    [self.fillColor set];
    NSRectFill(self.bounds);

    [self.strokeColor set];
    NSFrameRect(self.bounds);
}

    // Notice these don't do anything but call the eventDelegate. I could do whatever here, but I didn't.
    // The NICE thing about delgation is, the originating object stays in control of it sends to its delegate.
    // However, true to the meaning of the word 'delegate', once you pass something to the delegate, you have delegated some decision making power to that delegate object and no longer have any control (if you did, you might have a bad code smell in terms of the delegation design pattern.)
- (void)mouseDown:(NSEvent *)theEvent
{
    [self.eventDelegate view:self didHandleEvent:theEvent];
}

- (void)keyDown:(NSEvent *)theEvent
{
    [self.eventDelegate view:self didHandleEvent:theEvent];
}

@end

应用程序委托(和 eventDelegate!)实现

#import "AppDelegate.h"
    // Import the view class and if there were other files that implement any protocol
#import "EventDelegatingView.h"

    // Declare protocol conformance (or more accurately, not only import that protocol interface, but say you're going to implement it so the compiler can nag you if you don't)
@interface AppDelegate ()<EventDelegatingViewDelegate>

@property (weak) IBOutlet NSWindow *window;

    // For the simplest demo app we don't even need this property.
@property IBOutlet EventDelegatingView *eventDelegatingView;

@end

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    // Insert code here to initialize your application
}

- (void)applicationWillTerminate:(NSNotification *)aNotification {
    // Insert code here to tear down your application
}

    // It's all right here. Receive a reference to a view and a reference to an event, then do as you like with them.
#pragma mark - EventDelegatingViewDelegate
- (void)view:(NSView *)aView didHandleEvent:(NSEvent *)anEvent
{
    NSString *interestingEventNote;

    switch (anEvent.type) {
        case NSKeyDown:
        case NSKeyUp:
        {
                // For simplicity we won't try to figure out the modifier keys here.
            interestingEventNote = [NSString stringWithFormat:@"%@ key was pressed.", anEvent.charactersIgnoringModifiers];
        }
            break;

        case NSLeftMouseDown:
        {
            interestingEventNote = [NSString stringWithFormat:@"Left mouse down at point %@ in window", NSStringFromPoint(anEvent.locationInWindow)];
        }
            break;

        default:
            break;
    }

    NSLog(@"%@ %@ aView=%@\n note=%@", self, NSStringFromSelector(_cmd), aView, interestingEventNote?interestingEventNote:@"Nothing worth noting");
}

@end

这就是授权的权力。基本上它是各种回调,并且是构建一个类以使其能够根据需要在其他地方推迟某些东西的好方法。以一种相当懒惰、开放和松散耦合的方式将一些业务逻辑移动到正确的位置。

注意:我的代码示例显示使用应用程序委托。但校长是一样的。视图控制器只不过是一个委托,您可以根据需要添加尽可能多的内容。

于 2014-01-05T02:52:39.563 回答