我正在尝试找到一个允许我在视图控制器中获取keydown事件的解决方案。 我不相信默认情况下视图控制器是响应者链的一部分。
我很感激如何解决这个问题。我无法找到关于如何将VC添加到响应者链并获取事件的文档。
感谢。
Miek
答案 0 :(得分: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}];
}
答案 1 :(得分:2)
NSViewController
没有默认方法来执行此操作。但是,您可以通过继承NSView
来实现此目的。这是基本的想法:
keyDown
将活动发送给代表。 另一种方法是在NSNotifications
中发布keyDown
,并在视图控制器中观察和处理通知。其他方式也存在。
解释了代理方法的NSView子类
以下是带有NSView
子类的委托示例,该子类在其标头中声明了一个带有一个必需方法的协议,一个符合协议的IBOutlet
id属性。 NSView
子类在需要时将此方法调用到其委托。如果代表是nil,那在Cocoa中没问题。另请注意,切向上,我已将IB_Designable
和IBInspectable
添加到视图的颜色属性中。这允许在IB中设置它们并且需要10.10 SDK。
app委托已在NSView
实现文件中导入AppDelegate.m
子类,并在.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
App Delegate(和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
这就是授权的力量。基本上它是各种各样的回调,并且是一种很好的方法来构建一个类,使它能够按照需要将其他东西推迟。以一种相当懒惰,开放和松散耦合的方式将一些业务逻辑移动到正确的位置。
注意:我的代码示例显示了使用应用委托。但校长是一样的。视图控制器只是一个委托,您可以根据需要添加多少。
答案 2 :(得分:2)
在您的NSWidow(或NSWindowController)类实现中,将您的视图控制器设置为第一响应者:
[self makeFirstResponder:yourViewControllerInstance];
当然,您必须使您的NSViewController类对acceptsFirstResponder消息返回YES。