在 NSView 控制器中获取密钥关闭事件



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

我将不胜感激如何做到这一点的样本。我很难找到我能理解的有关如何将 VC 添加到响应程序链并获取事件的文档。

谢谢。

迈克

你可以实现这样的东西:

-(void) globalKeyDown: (NSNotification *) notification 

方法,然后只需在 awakeFromNib 中添加观察器...或控制器的加载视图方法

- (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}];
}
NSViewController没有

默认的方式来执行此操作。但是,您可以通过子类化NSView来实现此目的。这是基本思想:

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

另一种方法是在keyDown中发布NSNotifications,并在视图控制器中观察和处理通知。还存在其他方式。

NSView 子类与委托方法说明

下面是一个带有 NSView 子类的委托示例,该子类在其标头中声明了一个协议,其中包含一个必需的方法,即符合协议的 IBOutlet id 属性。NSView子类随时向其委托调用此方法。如果代表为零,那在可可中很好。另请注意,在切线方面,我已将IB_DesignableIBInspectable添加到视图的颜色属性中。这允许在 IB 中设置它们,并且需要 10.10 SDK。

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

另请注意,在 IB 中,我在窗口中添加了一个NSView,然后在检查器中将其类设置为自定义NSView子类。最后,我将其eventDelegate IBOutlet设置为 IB 中的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

应用委托(和事件委托!)实现

#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

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

注意:我的代码示例演示如何使用应用程序委托。但校长是一样的。视图控制器只不过是一个委托,您可以根据需要添加任意多或少。

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

[self makeFirstResponder:yourViewControllerInstance];

当然,您必须使 NSViewController 类向接受第一响应者消息返回"是"。

最新更新