为了响应 rightMouse 事件,我想调用一个显示上下文菜单、运行它并响应所选菜单项的函数。在 Windows 中,我可以使用带有 TPM_RETURNCMD 标志的 TrackPopupMenu。
在 Cocoa 中实现这一点的最简单方法是什么?似乎 NSMenu:popUpContextMenu 想要将事件发布到指定的 NSView。我必须创建一个虚拟视图并在返回之前等待事件吗?如果是这样,鉴于我没有返回我的 main ,我该如何“等待”或刷新事件?
为了响应 rightMouse 事件,我想调用一个显示上下文菜单、运行它并响应所选菜单项的函数。在 Windows 中,我可以使用带有 TPM_RETURNCMD 标志的 TrackPopupMenu。
在 Cocoa 中实现这一点的最简单方法是什么?似乎 NSMenu:popUpContextMenu 想要将事件发布到指定的 NSView。我必须创建一个虚拟视图并在返回之前等待事件吗?如果是这样,鉴于我没有返回我的 main ,我该如何“等待”或刷新事件?
在 Cocoa 中执行此操作的“正确”方法是让菜单项的目标和操作执行所需的方法。但是,如果您必须在初始调用中执行此操作,您可以使用它[NSView nextEventMatchingMask:]
来不断获取您感兴趣的新事件、处理它们并循环。这是一个等待直到释放鼠标右键的示例。您可能想要使用更复杂的掩码参数,并不断调用[NSView nextEventMatchingMask:]
,直到您得到您想要的。
NSEvent *localEvent = [[self window] nextEventMatchingMask: NSRightMouseUpMask];
我认为您会找到更容易的“正确”方法。
看来 popUpContextMenu 已经是同步的了。由于我没有看到使用 NSMenu 而不让它向 NSView 发送通知的方法,所以我想出了一个实例化临时 NSView 的方案。目标是显示弹出菜单并在单个函数调用的上下文中返回所选项目。以下是我提出的解决方案的代码片段:
// Dummy View class used to receive Menu Events
@interface DVFBaseView : NSView
{
NSMenuItem* nsMenuItem;
}
- (void) OnMenuSelection:(id)sender;
- (NSMenuItem*)MenuItem;
@end
@implementation DVFBaseView
- (NSMenuItem*)MenuItem
{
return nsMenuItem;
}
- (void)OnMenuSelection:(id)sender
{
nsMenuItem = sender;
}
@end
// Calling Code (in response to rightMouseDown event in my main NSView
void HandleRButtonDown (NSPoint pt)
{
NSRect graphicsRect; // contains an origin, width, height
graphicsRect = NSMakeRect(200, 200, 50, 100);
//-----------------------------
// Create Menu and Dummy View
//-----------------------------
nsMenu = [[[NSMenu alloc] initWithTitle:@"Contextual Menu"] autorelease];
nsView = [[[DVFBaseView alloc] initWithFrame:graphicsRect] autorelease];
NSMenuItem* item = [nsMenu addItemWithTitle:@"Menu Item# 1" action:@selector(OnMenuSelection:) keyEquivalent:@""];
[item setTag:ID_FIRST];
item = [nsMenu addItemWithTitle:@"Menu Item #2" action:@selector(OnMenuSelection:) keyEquivalent:@""];
[item setTag:ID_SECOND];
//---------------------------------------------------------------------------------------------
// Providing a valid windowNumber is key in getting the Menu to display in the proper location
//---------------------------------------------------------------------------------------------
int windowNumber = [(NSWindow*)myWindow windowNumber];
NSRect frame = [(NSWindow*)myWindow frame];
NSPoint wp = {pt.x, frame.size.height - pt.y}; // Origin in lower left
NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined
location:wp
modifierFlags:NSApplicationDefined
timestamp: (NSTimeInterval) 0
windowNumber: windowNumber
context: [NSGraphicsContext currentContext]
subtype:0
data1: 0
data2: 0];
[NSMenu popUpContextMenu:nsMenu withEvent:event forView:nsView];
NSMenuItem* MenuItem = [nsView MenuItem];
switch ([MenuItem tag])
{
case ID_FIRST: HandleFirstCommand(); break;
case ID_SECOND: HandleSecondCommand(); break;
}
}
除了不推荐使用的 Carbon 之外,没有直接的等价物。
要检测右键单击,请按照这些说明进行操作。它们确保您能够正确检测右键单击和按住不放,并在应该显示菜单时显示菜单,在不应该显示时不显示菜单。
对于以下事件,您可以尝试[[NSRunLoop currentRunLoop] runMode:NSEventTrackingRunLoopMode untilDate:[NSDate distantFuture]]
. 您需要反复调用它,直到用户选择了其中一个菜单项。
使用nextEventMatchingMask:NSRightMouseUpMask
不会在所有情况下,甚至在大多数情况下都有效。如果用户在您的控件上单击鼠标右键,鼠标右键会在它下降后立即上升,而无需选择菜单项,并且菜单项选择可能(尽管不一定)通过鼠标左键发生。最好重复运行运行循环,直到用户选择某些内容或关闭菜单。
我不知道如何判断用户在没有选择任何内容的情况下关闭了菜单。