自定义NSStatusItem和NSView无法可靠地接收NSTrackingEvents

时间:2012-07-17 15:05:11

标签: macos cocoa mouseevent nsstatusitem nstrackingarea

我有一个仅限状态栏项目的应用程序,我试图在mouseOver上显示一个面板。我有自定义状态项(和关联的视图)连接和工作,但跟踪rect只接收每十几个启动事件。这让我相信在某个地方发生了竞争状况,但我找不到它。在我的自定义状态栏项视图中:

- (id)initWithStatusItem:(NSStatusItem *)statusItem {
    CGFloat itemWidth = [statusItem length];
    CGFloat itemHeight = [[NSStatusBar systemStatusBar] thickness];
    NSRect itemRect = NSMakeRect(0.0, 0.0, itemWidth, itemHeight);
    NSLog(@"itemRect: %@", NSStringFromRect(itemRect));

    if ((self = [super initWithFrame:itemRect])) {
        _statusItem = statusItem;
        _statusItem.view = self;

        NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways;
        NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect:itemRect
                                                                    options:options
                                                                      owner:self
                                                                   userInfo:nil];
        [self addTrackingArea:trackingArea];

        [self.window setIgnoresMouseEvents:NO];
        [self.window setAcceptsMouseMovedEvents:YES];

        self.wantsLayer = YES;
    }
    return self;
}

- (void)mouseEntered:(NSEvent *)theEvent {
    [[NSNotificationCenter defaultCenter] postNotificationName:UAStatusItemMouseEnteredNotification object:nil];
}

- (void)mouseExited:(NSEvent *)theEvent {
    [[NSNotificationCenter defaultCenter] postNotificationName:UAStatusItemMouseExitedNotification object:nil];
}

在大多数发布时,应用都不会响应跟踪鼠标事件,但每隔一段时间,mouseEntered:mouseExited:方法都会被正确调用,这让我很困惑。这里发生了什么,我做错了什么?




编辑07/17/2012
我根据@ Streams的答案修改了代码,但看到同样的问题:

- (id)initWithStatusItem:(NSStatusItem *)statusItem {
    CGFloat itemWidth = [statusItem length];
    CGFloat itemHeight = [[NSStatusBar systemStatusBar] thickness];
    NSRect itemRect = NSMakeRect(0.0, 0.0, itemWidth, itemHeight);
    NSLog(@"itemRect: %@", NSStringFromRect(itemRect));

    if ((self = [super initWithFrame:itemRect])) {
        _statusItem = statusItem;
        _statusItem.view = self;            

        [self updateTrackingAreas];

        [self.window setIgnoresMouseEvents:NO];
        [self.window setAcceptsMouseMovedEvents:YES];

        self.wantsLayer = YES;
    }
    return self;
}

- (void)updateTrackingAreas {

    if (self.trackingArea)
        [self removeTrackingArea:self.trackingArea];

    [super updateTrackingAreas];

    self.trackingArea = [[NSTrackingArea alloc] initWithRect:CGRectZero
                                                     options:NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingInVisibleRect | NSTrackingActiveAlways
                                                       owner:self
                                                    userInfo:nil];
    [self addTrackingArea:self.trackingArea];
}




编辑07/18/2012
这是一个准系统sample project,它使用一个众所周知的github项目(由@Stream编写)来显示问题。如果有的话,它无法可靠地接收鼠标悬停事件。

2 个答案:

答案 0 :(得分:2)

我打开了一个DTS请求让Apple看看这个。以下是回复:

  

...启动应用时,您在Xcode中使用全屏。一世   在[之前]没有这样做,但我现在可以重现这个问题。从我能做到的   告诉它只有在你的应用程序从全屏模式启动时才会发生   Xcode中。您的用户不会以这种方式启动应用。这是一个   AppKit的fullScreen模式存在问题,而不一定是你的   代码。

答案 1 :(得分:0)

我认为您应该只在-[NSView updateTrackingAreas]管理跟踪区域。例如:

- (void)updateTrackingAreas
{
    if (_trackingArea) {
        [self removeTrackingArea:_trackingArea];
    }

    [super updateTrackingAreas];

    NSTrackingAreaOptions options = (NSTrackingMouseEnteredAndExited |
                                     NSTrackingMouseMoved |
                                     NSTrackingInVisibleRect |
                                     NSTrackingActiveAlways);
    _trackingArea = [[NSTrackingArea alloc] initWithRect:CGRectZero
                                                 options:options
                                                   owner:self
                                                userInfo:nil];
    [self addTrackingArea:_trackingArea];
}