【问题标题】:NSPopover from NSMenuItem (Button) does not accept mouse events来自 NSMenuItem (Button) 的 NSPopover 不接受鼠标事件
【发布时间】:2021-11-29 12:42:00
【问题描述】:

我想知道是否有人知道为什么当从 NSMenu 内的 NSMenuItem 内的按钮打开 NSPopover 时,它不响应鼠标事件(悬停、单击)。

如果有解决这个问题的方法?

这是一个将 NSMenu 附加到其视图的小示例视图控制器。该菜单有一个按钮,可在单击时打开弹出框,以及一些虚拟项目,即使弹出框位于它们上方,它们仍会显示它们仍然接收鼠标事件:

@implementation MyViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSMenu *menu = [NSMenu new];
    /// Some Dummy Items to show that the popover doesn’t accept the mouse.
    NSArray *dummyItems = @[@"item1", @"item2", @"item3"];
    for (NSString *itemName in dummyItems) {
        NSMenuItem *item = [NSMenuItem new];
        item.title = itemName;
        item.target = self;
        item.action = @selector(doNothing:);
        [menu addItem:item];
    }
    
    /// The button which presents the popover on click
    NSMenuItem *item = [NSMenuItem new];
    NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 30)];
    button.target = self;
    button.action = @selector(showPopover:);
    button.title = @"Show Popover";
    item.view = button;
    [menu addItem:item];
    
    [self.view setMenu:menu];
}

- (void)showPopover:(NSButton *)sender {
    /// This popover does not receive the mouse events for some reason.
    NSPopover *popover = [NSPopover new];
    NSViewController *popoverVC = [NSViewController new];
    NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 140, 25)];
    button.title = @"I’m not clickable";
    button.target = self;
    button.action = @selector(showPopover:);
    popoverVC.view = button;
    [popover setContentViewController:popoverVC];
    [popover showRelativeToRect:sender.frame ofView:sender.superview preferredEdge:NSMaxYEdge];
    [button.window makeKeyWindow];   /// Does not help
    [button.window becomeKeyWindow]; /// Does not help
}

- (void)doNothing:(id)sender {}

@end

【问题讨论】:

    标签: objective-c macos cocoa


    【解决方案1】:

    有一个解决方案,但它可能没有用,具体取决于您要执行的操作。我无法运行您发布的代码,但可以看到您在菜单和弹出窗口中都添加了一个按钮。问题似乎是用于显示弹出框的矩形。由于我不知道的原因,如果我们尝试根据菜单项按钮的框架显示弹出框,则无法单击弹出框按钮。但是,如果弹出框显示基于基于窗口 contentView 的控件的框架,例如 NSPopUpButton 或位于菜单附近的 NSView 的矩形,则弹出框按钮将变为可点击。由于附近没有矩形,从菜单栏中删除的菜单更具挑战性。通过删除预先存在的 main.m 代码并将以下内容复制/粘贴到其中,可以在 Xcode objc 项目中运行此演示。还需要删除预先存在的 AppDelegate 文件以避免重复符号。该演示说明了使用 NSView 矩形和 NSPopUpButton 框架来显示弹出框,其中任何一个都将允许可点击的弹出框按钮。失败的代码会被移除。

    #import <Cocoa/Cocoa.h>
    
    @interface PopoverController: NSViewController
    @end
    
    @implementation PopoverController
    @end
    
    
    @interface AppDelegate : NSObject <NSApplicationDelegate> {
     NSWindow *window;
     NSPopover *popover;
     NSView *popoverView;
     NSMenuItem *menuItem;
     NSMenu *menu;
     PopoverController *popoverController;
     NSPopUpButton *pullDwn;
     NSView *menuView;
    }
    
    - (void) showPopoverAction:(id)sender;
    - (void) menuAction:(id)sender;
    - (void) myBtnAction:(id)sender;
    - (void) buildMenu;
    - (void) buildWnd;
    @end
    
    @implementation AppDelegate
    
    
    - (void) showPopoverAction:(id)sender {
    // **** This works **** //
    //[popover showRelativeToRect:pullDwn.bounds ofView:pullDwn preferredEdge:NSMaxXEdge];
    [popover showRelativeToRect:menuView.bounds ofView:menuView preferredEdge:NSMaxXEdge];
    // **** This doesn't **** //
    //[popover showRelativeToRect:[menuItem.view bounds] ofView:menuItem.view preferredEdge:NSMaxXEdge];
    }
    
    - (void) myBtnAction: (id)sender {
     NSBeep();
     NSLog(@"Popover button hit.");
     NSLog(@"===================");
    }
    
    - (void) menuAction: (id)sender {
    [popover showRelativeToRect:pullDwn.bounds ofView:pullDwn preferredEdge:NSMaxXEdge];
    }
    
    - (void) buildMenu {
     NSMenu *menubar = [NSMenu new];
     NSMenuItem *menuBarItem = [NSMenuItem new];
     [menubar addItem:menuBarItem];
     [NSApp setMainMenu:menubar];
     NSMenu *appMenu = [NSMenu new];
     NSMenuItem *quitMenuItem = [[NSMenuItem alloc] initWithTitle:@"Quit" action:@selector(terminate:) keyEquivalent:@"q"];
     [appMenu addItem:quitMenuItem];
     [menuBarItem setSubmenu:appMenu];
    }
    
    - (void) buildWnd {
    
    #define _wndW  500
    #define _wndH  350
    
    window = [[NSWindow alloc] initWithContentRect: NSMakeRect( 0, 0, _wndW, _wndH )
    styleMask: NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable
    backing: NSBackingStoreBuffered defer: NO];
    
    [window center];
    [window setTitle: @"NSPopUpButton Menu"];
    [window makeKeyAndOrderFront: nil];
    
    // ******* Popover controller ********* //
    popoverController = [[PopoverController alloc] init];
    
    // **** Menu View **** //
    menuView = [[NSView alloc]initWithFrame:NSMakeRect( 100, _wndH - 242, 130, 30 ) ];
    [[window contentView] addSubview:menuView];
    
    // ****** Pull-Down NSPopUpButton ******* //
    // First array element (0) becomes the title
    NSArray *menuItems = [NSArray arrayWithObjects: @"Pull-Down", @"Item 1", @"Item 2",@"Item 3",nil];
    pullDwn = [[NSPopUpButton alloc] initWithFrame:NSMakeRect( 100, _wndH - 142, 130, 30 )];
     menu = pullDwn.menu;
     menuItem = [NSMenuItem new];
     NSButton *myBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 30, 30, 95, 30 )];
    [myBtn setBezelStyle:NSBezelStyleRounded ];
    [myBtn setTitle: @"Popover"];
    [myBtn setAction: @selector (showPopoverAction:)];
    menuItem.view = myBtn;
    [pullDwn setPullsDown:YES];
    [pullDwn addItemsWithTitles:menuItems];
    [pullDwn setTarget:self];
    [pullDwn setAction:@selector(menuAction:)];
    [menu addItem:menuItem];
    [[window contentView]addSubview:pullDwn];
    
    // **** NSPopover **** //
     popover = [[NSPopover alloc] init];
     [popover setContentViewController:popoverController];
     [popover setContentSize:NSMakeSize(150, 100)];
     //[popover setBehavior:NSPopoverBehaviorTransient];
     [popover setBehavior:NSPopoverBehaviorSemitransient];
     //[popover setBehavior:NSPopoverBehaviorApplicationDefined];
     [popover setAnimates: YES];
     [popover setDelegate: self];
     
    // ****** Popover view ****** //
     popoverView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, 150, 100)];
    
    //******* Popover text field ******* //
    NSTextField *ef = [[NSTextField alloc] initWithFrame:NSMakeRect( 20, 20, 110, 24 )];
    [ef setStringValue:@"EditFld"];
    [ef setAlignment:NSTextAlignmentCenter];
    [ef setDrawsBackground:NO];
    [popoverView addSubview:ef];
    
    // **** Popover Button **** //
    NSButton *popoverBtn =[[NSButton alloc]initWithFrame:NSMakeRect( 20, 50, 95, 24 )];
    [popoverBtn setBezelStyle:NSBezelStyleRounded ];
    [popoverBtn setTitle: @"Push me"];
    popoverBtn.target = self;
    popoverBtn.action = @selector(myBtnAction:);
    [popoverView addSubview: popoverBtn];
    [popoverController setView:popoverView];
    
    // ***** Quit btn ***** //
    NSButton *quitBtn = [[NSButton alloc]initWithFrame:NSMakeRect( _wndW - 50, 5, 40, 40 )];
    [quitBtn setBezelStyle:NSBezelStyleCircular ];
    [quitBtn setTitle: @"Q" ];
    [quitBtn setAutoresizingMask: NSViewMinXMargin];
    [quitBtn setAction:@selector(terminate:)];
    [[window contentView] addSubview: quitBtn];
    }
    
    - (void) applicationWillFinishLaunching: (NSNotification *)notification {
    [self buildMenu];
    [self buildWnd];
    }
    
    - (void) applicationDidFinishLaunching: (NSNotification *)notification {
    }
    @end
    
    int main () {
    NSApplication *application = [NSApplication sharedApplication];
    AppDelegate *appDelegate = [[AppDelegate alloc] init];
    [application setDelegate:appDelegate];
    [application run];
    return 0;
    }
    
    

    【讨论】:

    • 您好,非常感谢! 1. 我不明白为什么我的代码不会执行,只需将其粘贴到基于单个应用程序 nib 的默认新 Xcode 项目中即可。它会打开一个带有菜单的空窗口,该菜单在右键单击其 contentView 中的任意位置时显示。但无论如何,我看了你的样本,即使它有点工作,它似乎对我的情况没有帮助。目标是拥有 3 个颜色井按钮,在弹出窗口中显示颜色面板。与弹出框交互时,菜单也不会关闭。我非常感谢你的帮助。不过,我的计划似乎行不通
    • 你能发布一个 Xcode 项目的链接来演示这个问题吗?
    猜你喜欢
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多