macos NSButton 的弹出菜单实现
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9716385/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Popup menu implementation from NSButton
提问by Dr.Kameleon
How should I go about it?
我该怎么办?
I was thinking about...
我在想...
[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];
回答by arun.s
Yup.
对。
On button action call
按钮操作调用
[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];
where
在哪里
menu
: menu you want to showsender
: button you clickedevent
: a newNSEvent
you create
menu
: 要显示的菜单sender
:你点击的按钮event
: 一个NSEvent
你创造的新
When you create the new NSEvent
, specify the location as to where you want the popup menu to be shown.
创建新的 时NSEvent
,请指定要显示弹出菜单的位置。
回答by Kaunteya
Swift version of accepted answer
已接受答案的 Swift 版本
@IBAction func actionOccurred(sender: NSButton) {
if let event = NSApplication.sharedApplication().currentEvent {
NSMenu.popUpContextMenu(sender.menu!, withEvent: event, forView: sender)
}
}
Updated answer
更新答案
Swift 5.1 version
斯威夫特 5.1 版本
Add NSMenu to the NSViewController in storyboard as seen in the image
如图所示,将 NSMenu 添加到故事板中的 NSViewController
@IBOutlet var userMenu: NSMenu!
@IBAction func menuClicked(_ sender: NSButton) {
var location = NSEvent.mouseLocation
location.x -= 10; location.y -= 10 // Menu appears below the button
userMenu.popUp(positioning: userMenu.item(at: 0), at: location, in: nil)
}
回答by Jonathan Mitchell
As I have commented I find the ButtonMadness example less than perfect. My implementation seems to work better. The menu is shown on mouse down, the button remains depressed throughout, the menu position can be specified and the menu is dismissed without subsequent spurious display.
正如我所评论的,我发现 ButtonMadness 示例并不完美。我的实现似乎效果更好。菜单在鼠标按下时显示,按钮始终保持按下状态,可以指定菜单位置并取消菜单,而不会出现后续虚假显示。
To be honest NSPopupButton is a better choice in the majority of situations. I use this code mainly because of the convenience of having one class for buttons and popups and because the menu does not contain the popup control image and title. I load the menu from a separate nib and reuse it as is elsewhere in the app as required.
老实说,在大多数情况下,NSPopupButton 是更好的选择。我使用这段代码主要是因为有一个按钮和弹出窗口的类很方便,而且菜单不包含弹出控件图像和标题。我从一个单独的笔尖加载菜单,并根据需要在应用程序的其他地方重新使用它。
Note that it is trivial to add additional support for say a popover as well as menu.
请注意,为弹出框和菜单添加额外支持是微不足道的。
NSButton subclass:
- (void)mouseDown:(NSEvent *)theEvent {
// if a menu is defined let the cell handle its display
if (self.menu) {
if ([theEvent type] == NSLeftMouseDown) {
[[self cell] setMenu:[self menu]];
} else {
[[self cell] setMenu:nil];
}
}
[super mouseDown:theEvent];
}
NSButtonCell subclass:
- (BOOL)trackMouse:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp
{
// if menu defined show on left mouse
if ([event type] == NSLeftMouseDown && [self menu]) {
NSPoint result = [controlView convertPoint:NSMakePoint(NSMidX(cellFrame), NSMidY(cellFrame)) toView:nil];
NSEvent *newEvent = [NSEvent mouseEventWithType: [event type]
location: result
modifierFlags: [event modifierFlags]
timestamp: [event timestamp]
windowNumber: [event windowNumber]
context: [event context]
eventNumber: [event eventNumber]
clickCount: [event clickCount]
pressure: [event pressure]];
// need to generate a new event otherwise selection of button
// after menu display fails
[NSMenu popUpContextMenu:[self menu] withEvent:newEvent forView:controlView];
return YES;
}
return [super trackMouse:event inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
}
回答by sim
Recently, I was trying to implement it and I came, as I think, with a simpler solution
最近,我正在尝试实施它,正如我所想的那样,我带来了一个更简单的解决方案
-(IBAction)buttonClick:(id)sender {
NSButton * b = (NSButton*)sender;
NSPoint l = [ self.window convertBaseToScreen:b.frame.origin ];
[ self.menu popUpMenuPositioningItem:nil atLocation:l inView:nil ];
}
Update
更新
convertBaseToScreen
is deprecated starting from 10.7, instead of it use convertRectToScreen
in the following way:
convertBaseToScreen
从 10.7 开始弃用,而不是convertRectToScreen
按以下方式使用:
NSPoint l = [self.window convertRectToScreen:b.frame].origin;
回答by Pierre Houston
Using a context menu on the action call isn't a great way to do it because the menu doesn't show until mouseUp - you don't get the hold & drag menu behavior. Apple's ButtonMadness sample shows how to really do this in a subclass of NSButton, see DropDownButton. https://developer.apple.com/library/mac/samplecode/ButtonMadness/Introduction/Intro.html
在操作调用上使用上下文菜单并不是一个好方法,因为菜单直到 mouseUp 才会显示 - 您不会获得按住和拖动菜单行为。Apple 的 ButtonMadness 示例展示了如何在 NSButton 的子类中真正做到这一点,请参阅 DropDownButton。https://developer.apple.com/library/mac/samplecode/ButtonMadness/Introduction/Intro.html
Summarizing that subclass: create a NSPopUpButtonCell with pullsDown set to YES & preferredEdge to NSMaxYEdge, copy your menu to add a blank top item and set it as that cell's menu, on mouseDown call [thePopUpCell performClickWithFrame:self.bounds inView:self] and set self.needsDisplay
总结该子类:创建一个 NSPopUpButtonCell 并将 pullsDown 设置为 YES & preferredEdge 到 NSMaxYEdge,复制您的菜单以添加一个空白的顶部项目并将其设置为该单元格的菜单,在 mouseDown 调用 [thePopUpCell performClickWithFrame:self.bounds inView:self] 并设置自我需求展示
回答by ByungBok Lee
Do like that.
这样做。
-(IBAction)onClickSourceAdd:(id)sender {
NSMenu *mainMenu = [NSApp mainMenu];
NSMenu *sourceMenu = [[mainMenu itemAtIndex:2] submenu];
NSMenu *addMenu = [[sourceMenu itemAtIndex:0] submenu];
[NSMenu popUpContextMenu:addMenu
withEvent:[NSApp currentEvent]
forView:(NSButton *)sender];
}