丰富的 Window-like 上下文菜单(如 Interface Builder)

Rich, Window-like Context Menu (like Interface Builder)

我需要一个上下文菜单,其功能类似于 Interface Builder 在右键(控制)单击视图、视图控制器等时显示的菜单:

乍一看,它看起来像一个 NSPanel,其样式属性设置为 "HUD Panel",包含某种大纲视图。

window 本身应该不难实现,但在右键(控制)单击时显示上下文菜单的通常方法是重写方法:

func menu(for event: NSEvent) -> NSMenu?

...将 NSMenu 作为 return 值;不能传递 NSWindow / NSPanel


也许我可以这样做:

override func menu(for event: NSEvent) -> NSMenu? {

    // Create our popup window (HUD Panel) and present it
    // at the location of event:

    // (...actual code omitted...)

    // Prevent any actual menu from being displayed: 
    return nil 
}

...但感觉像是 hack;我通过 假装关心 呈现实际 [=14] 来欺骗系统放弃右(控制)-click 事件的 时间 =](即,重写明确用于此的方法),但使用该时间做不同的事情

我还需要放置一些逻辑来在用户单击其他地方时关闭 window(上下文菜单内置了此功能)。

我认为子类化 NSMenuNSMenuItem 来获得上述行为和外观也不可行...

有没有更好的方法? 有人知道(或能够猜到)Interface Builder 实际做什么吗?


编辑: 正如@Willeke 在评论中指出的那样,要显示的面板的条件与上下文菜单不完全相同,所以它肯定是不是一个。这意味着劫持上述方法以显示 window 不仅不优雅,而且是错误的。问题是关于 如何显示 Window(即检测静态、非拖动右键单击)。

您需要从您的视图子类中覆盖 rightMouseDown(with:) 并使用它来触发显示面板。 NSView's implementation of that method 调用 menu(for:) 并显示返回的菜单,因此您的自定义子类可以使用它来显示其自定义菜单面板,而不是调用 super.

为了与标准上下文菜单和 Interface Builder 中的菜单在行为上完全一致,您还需要通过覆盖 mouseDown(with:) 来处理 ctrl-left-clicks 并检查事件是否 modifierFlags 包括 .control.