【发布时间】:2012-03-15 08:46:02
【问题描述】:
我应该怎么做?
我在想……
[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];
【问题讨论】:
标签: objective-c macos cocoa
我应该怎么做?
我在想……
[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];
【问题讨论】:
标签: objective-c macos cocoa
是的。
按钮动作调用
[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];
在哪里
menu : 你要显示的菜单 sender : 你点击的按钮event :您创建的新 NSEvent
当您创建新的NSEvent 时,请指定您希望显示弹出菜单的位置。
【讨论】:
-[NSMenu popUp:...] 而不是类方法。这样,即使您使用键盘快捷键,它也会相对于您的按钮定位。
已接受答案的 Swift 版本
@IBAction func actionOccurred(sender: NSButton) {
if let event = NSApplication.sharedApplication().currentEvent {
NSMenu.popUpContextMenu(sender.menu!, withEvent: event, forView: sender)
}
}
将 NSMenu 添加到情节提要中的 NSViewController,如图所示
右键单击故事板中的按钮并将菜单出口连接到我们刚刚添加到故事板中的菜单(图中箭头指向的位置)
@IBAction func menuClicked(_ sender: NSButton) {
var location = NSEvent.mouseLocation
location.x -= 10; location.y -= 10 // Menu appears below the button
let menu = sender.menu!
menu.popUp(positioning: menu.item(at: 0), at: location, in: nil)
}
【讨论】:
正如我所评论的,我发现 ButtonMadness 示例并不完美。 我的实现似乎效果更好。菜单在鼠标按下时显示,按钮始终保持按下状态,可以指定菜单位置,菜单在没有后续虚假显示的情况下被关闭。
说实话,NSPopupButton 在大多数情况下都是更好的选择。我使用这个代码主要是因为有一个类用于按钮和弹出窗口很方便,并且菜单不包含弹出控件图像和标题。我从一个单独的 nib 加载菜单并根据需要在应用程序的其他地方重复使用它。
请注意,添加对弹出框和菜单的额外支持是微不足道的。
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];
}
【讨论】:
最近,我试图实现它,但我想,我带来了一个更简单的解决方案
-(IBAction)buttonClick:(id)sender {
NSButton * b = (NSButton*)sender;
NSPoint l = [ self.window convertBaseToScreen:b.frame.origin ];
[ self.menu popUpMenuPositioningItem:nil atLocation:l inView:nil ];
}
更新
convertBaseToScreen 从 10.7 开始被弃用,而不是使用 convertRectToScreen,如下所示:
NSPoint l = [self.window convertRectToScreen:b.frame].origin;
【讨论】:
NSPoint point = [[self.view window] convertRectToScreen:((NSButton*)sender).frame].origin; 有什么想法?
在操作调用上使用上下文菜单并不是一个好方法,因为菜单直到 mouseUp 才会显示 - 您不会获得按住和拖动菜单的行为。 Apple 的 ButtonMadness 示例展示了如何在 NSButton 的子类中真正做到这一点,请参阅 DropDownButton。 https://developer.apple.com/library/mac/samplecode/ButtonMadness/Introduction/Intro.html
总结该子类:创建一个 NSPopUpButtonCell 并将 pullsDown 设置为 YES 并将preferredEdge 设置为 NSMaxYEdge,复制您的菜单以添加一个空白顶部项目并将其设置为该单元格的菜单,在 mouseDown 调用 [thePopUpCell performClickWithFrame:self.bounds inView:self ] 并设置 self.needsDisplay
【讨论】:
这样做。
-(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];
}
【讨论】: