NSButton的弹出菜单实现

时间:2012-03-15 08:46:02

标签: objective-c macos cocoa

我应该怎么做?

我在考虑......

[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];

6 个答案:

答案 0 :(得分:26)

烨。

按钮操作调用

[NSMenu popUpContextMenu:menu withEvent:event forView:(NSButton *)sender];

,其中

  • menu:您要显示的菜单
  • sender:您点击的按钮
  • event:您创建的新NSEvent

创建新NSEvent时,请指定您希望弹出菜单显示位置的位置。

答案 1 :(得分:10)

Swift版本的已接受答案

@IBAction func actionOccurred(sender: NSButton) {
    if let event = NSApplication.sharedApplication().currentEvent {
        NSMenu.popUpContextMenu(sender.menu!, withEvent: event, forView: sender)
    }
}

答案 2 :(得分:6)

正如我所评论的那样,我发现ButtonMadness的例子并不完美。 我的实现似乎更好。鼠标按下时显示菜单,整个按钮保持按下状态,可以指定菜单位置,菜单将被解除,不会出现虚假显示。

说实话,在大多数情况下,NSPopupButton是更好的选择。我使用这段代码主要是因为按钮和弹出窗口有一个类的便利,因为菜单不包含弹出控件图像和标题。我从单独的笔尖加载菜单,并根据需要在应用程序的其他位置重复使用它。

请注意,为弹出窗口和菜单添加额外的支持是微不足道的。

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];
}

答案 3 :(得分:6)

最近,我试图实现它,我认为,我用一个更简单的解决方案

-(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; 

答案 4 :(得分:4)

在动作调用中使用上下文菜单不是一个很好的方法,因为菜单直到mouseUp才显示 - 你没有得到保持&amp;拖动菜单行为。 Apple的ButtonMadness示例演示了如何在NSButton的子类中真正做到这一点,请参阅DropDownButton。 https://developer.apple.com/library/mac/samplecode/ButtonMadness/Introduction/Intro.html

总结该子类:创建一个NSPopUpButtonCell,并将pullsDown设置为YES&amp; preferredEdge to NSMaxYEdge,复制你的菜单以添加一个空白的顶级项目并将其设置为该单元格的菜单,在mouseDown调用[thePopUpCell performClickWithFrame:self.bounds inView:self]并设置self.needsDisplay

答案 5 :(得分:0)

这样做。

    -(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]; 
     }