场景
-
Cocoa
开发的时候经常会遇到需要上下文菜单的情况, 当然这种菜单不是菜单栏里的菜单, 而是根据数据多少展现不同的子菜单。这就需要动态创建子菜单,问题是如何创建?如何绑定SEL
, 如何加入子菜单标识,以便在点击后知道点击了那个菜单. -
菜单弹出, 之后呢?如何在指定位置弹出?比如一个按钮正下方,贴着按钮的底部.
说明
创建上下文菜单有3种方法:
方法 1
在 Interface Builder
配置. 添加一个独立的无父窗口的菜单到nib
文件, 包括连接的target
和action
. 接着连接到你的自定义NSView
的Outlet menu
.
方法 2
用编程的方式分配一个基本的menu
. 重载自定义NSView
的类方法defaultMenu
返回一个默认的menu
. 这个默认的菜单也可以通过访问NSResponder
的menu
方法获取到, 除非其他NSMenu
已经关联这个view
.
方法 3
用编程的方式分配一个实例menu
. 在自定义的view
的initWithFrame
或者awakeFromNib
方法, 创建这个menu
并且调用NSView
的setMenu(NSResponder)
方法.
弹出上下文菜单有两种方法
通过绑定setMenu
方式, 在view
点击右键会自动弹出菜单, 有两种方式可以对菜单进行调整.
方法 1
设置menu
的代理, 之后实现以下的代理(NSMenuDelegate
)方法,可以对menu
进行修改.
- (void)menuWillOpen:(NSMenu *)menu;
方法 2
重载view
的mouseDown
方法,之后添加如下的实现, 编程创建子菜单, 这种方式适合动态创建不定数量的子菜单.
- (void)mouseDown:(NSEvent *)theEvent {
NSMenu *theMenu = [[NSMenu alloc] initWithTitle:@"Contextual Menu"];
[theMenu insertItemWithTitle:@"Beep" action:@selector(beep:) keyEquivalent:@"" atIndex:0];
[theMenu insertItemWithTitle:@"Honk" action:@selector(honk:) keyEquivalent:@"" atIndex:1];
[NSMenu popUpContextMenu:theMenu withEvent:theEvent forView:self];
}
方法 3
如果只是需要点击一个按钮需要弹出上下文菜单, 而不是重载mouseDown
方法, 那么需要我们自定义NSEvent
NSMenu* phoneSelectMenu = [phoneSelect menu];
[phoneSelectMenu removeAllItems];
for(int i = 0; i<mm.size();++i){
auto one = mm[i];
NSMenuItem* item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithUTF8String:one->name.c_str()] action:@selector(onItemSelect:) keyEquivalent:@""] autorelease];
[item setTarget:self];
[item setRepresentedObject:[NSString stringWithUTF8String:one->_id.c_str()]];
[phoneSelectMenu addItem:item];
}
// 计算菜单显示在按钮phoneSelect正下方
NSPoint fp = phoneSelect.frame.origin;
NSPoint fp_base = [self convertPoint:fp toView:nil];
fp_base.y-=phoneSelect.frame.size.height;
NSEvent* event = [NSEvent mouseEventWithType:NSLeftMouseUp location:fp_base modifierFlags:NSEventSwipeTrackingLockDirection timestamp:0 windowNumber:[[phoneSelect window] windowNumber] context:nil eventNumber:0 clickCount:0 pressure:0];
[NSMenu popUpContextMenu:phoneSelectMenu withEvent:event forView:phoneSelect];