NSMenuItem中的自定义NSView未接收鼠标事件

时间:2009-09-08 18:31:48

标签: cocoa nsmenuitem nsstatusitem

我使用popUpStatusItemMenu从NSStatusItem弹出一个NSMenu。这些NSMenuItems显示了一堆不同的链接,每个链接都与setAction:连接到目标的openLink:方法。这种安排长期以来一直很好。用户从菜单中选择一个链接,然后openLink:方法处理它。

不幸的是,我最近决定尝试使用NSMenuItem的setView:方法来提供更好/更滑动的界面。基本上,我刚停止设置标题,创建了NSMenuItem,然后使用setView:来显示自定义视图。这非常有效,菜单项看起来很棒,我的自定义视图也会显示出来。

但是,当用户选择菜单项并释放鼠标时,该操作不再起作用(即,不调用openLink:)。如果我只是简单地注释掉setView:call,那么动作再次起作用(当然,菜单项是空白的,但动作正确执行)。那么,我的第一个问题就是设置视图会破坏NSMenuItem的操作。

没问题,我想,我会通过在自定义视图中检测mouseUp事件并从那里调用我的action方法来修复它。我将此方法添加到我的自定义视图中:

- (void)mouseUp:(NSEvent *)theEvent {
  NSLog(@"in mouseUp");
  }

没有骰子!永远不会调用此方法。

我可以设置跟踪rects并接收mouseEntered:事件。我在mouseEntered例程中进行了一些测试,如下所示:

if ([[self window] ignoresMouseEvents]) {  NSLog(@"ignoring mouse events");  }
else {  NSLog(@"not ignoring mouse events");  }
if ([[self window] canBecomeKeyWindow]) {  dNSLog((@"canBecomeKeyWindow"));  }
else {  NSLog(@"not canBecomeKeyWindow");  }
if ([[self window] isKeyWindow]) {  dNSLog((@"isKeyWindow"));  }
else {  NSLog(@"not isKeyWindow");  }

得到以下回复:

not ignoring mouse events
canBecomeKeyWindow
not isKeyWindow

这是问题吗? “not isKeyWindow”?据推测,这并不好,因为Apple的文档说“如果用户点击不在关键窗口中的视图,默认情况下窗口会被提前并变为密钥,但不会调度鼠标事件。”但必须有办法检测这些事件。怎么样?

添加:

[[self window] makeKeyWindow];

无效,尽管canBecomeKeyWindow为YES。

7 个答案:

答案 0 :(得分:12)

将此方法添加到自定义NSView中,它可以正常使用鼠标事件

- (void)mouseUp:(NSEvent*) event {
    NSMenuItem* mitem = [self enclosingMenuItem];
    NSMenu* m = [mitem menu];
    [m cancelTracking];
    [m performActionForItemAtIndex: [m indexOfItem: mitem]];
}

但是我遇到了关键操作的问题,如果你解决了这个问题,也许你可以回答我的问题,并帮助我一点点。

答案 1 :(得分:9)

将此添加到您的自定义视图中,您应该没问题:

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

答案 2 :(得分:4)

我将此方法添加到我的自定义视图中,现在一切都运行得很漂亮:

- (void)viewDidMoveToWindow {
    [[self window] becomeKeyWindow];
}

希望这有帮助!

答案 3 :(得分:1)

我已经为SwiftUI Swift 5.3更新了该版本:

final class HostingView<Content: View>: NSHostingView<Content> {
    override func viewDidMoveToWindow() {
        window?.becomeKey()
    }
}

然后像这样使用:

let item = NSMenuItem()
let contentView = ContentView()
item.view = HostingView(rootView: contentView)

let menu = NSMenu()
menu.items = [item]

答案 4 :(得分:0)

到目前为止,实现该目标的唯一方法是在updateTrackingAreas中手动注册一个跟踪区域-值得庆幸的是,就像这样:

override func updateTrackingAreas() {
    let trackingArea = NSTrackingArea(rect: bounds, options: [.enabledDuringMouseDrag, .mouseEnteredAndExited, .activeInActiveApp], owner: self, userInfo: nil)
    addTrackingArea(trackingArea)
}

答案 5 :(得分:-1)

最近我需要显示NSStatusItem的自定义视图,在点击它时显示常规NSMenu并支持状态图标上的拖放操作。

我主要使用this问题中的三个不同来源解决了我的问题。

希望它可以帮助其他人。

答案 6 :(得分:-1)

请参阅名为CustomMenus的Apple示例代码 在那里,你会在ImagePickerMenuItemView类中找到一个很好的例子。

在菜单中创建一个类似普通NSMenuItem的视图并不简单或微不足道。 有一些真正的决定和编码要做。