Есть ли в Какао эквивалентный метод для синхронного TrackPopupMenu в Windows?
-
03-07-2019 - |
Вопрос
В ответ на событие rightMouse я хочу вызвать функцию, которая отображает контекстное меню, запускает его и отвечает на выбранный пункт меню. В Windows я могу использовать TrackPopupMenu с флагом TPM_RETURNCMD.
Какой самый простой способ реализовать это в Какао? Кажется, NSMenu: popUpContextMenu хочет опубликовать событие в указанном NSView. Должен ли я создать фиктивный вид и дождаться события, прежде чем вернуться? Если да, то как мне «ждать»? или сбросить события, если я не вернусь на главную?
Решение 2
Похоже, что 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;
}
}
Другие советы
«Правильный» способ сделать это в Какао - заставить целевой элемент меню и действие выполнить требуемый метод. Однако, если вы должны сделать это во время вашего первоначального вызова, вы можете использовать [NSView nextEventMatchingMask:]
, чтобы постоянно получать новые события, которые вас интересуют, обрабатывать их и выполнять цикл. Вот пример, который просто ждет, пока не будет отпущена правая кнопка мыши. Возможно, вы захотите использовать более сложный аргумент маски и постоянно вызывать [NSView nextEventMatchingMask:]
, пока не получите то, что хотите.
<код> код>
NSEvent *localEvent = [[self window] nextEventMatchingMask: NSRightMouseUpMask];
Я думаю, вы найдете «правильный» способ пойти намного проще.
Прямого эквивалента не существует, кроме как в Carbon, который не рекомендуется.
Чтобы обнаружить щелчок правой кнопкой мыши, следуйте эти инструкции . Они гарантируют, что вы будете правильно определять щелчки правой кнопкой мыши и удерживать их правой кнопкой мыши, а также отображать меню, когда должны, и не отображать его, когда не должны.
Для следующих событий вы можете попробовать [[NSRunLoop currentRunLoop] runMode: NSEventTrackingRunLoopMode tillDate: [NSDate distantFuture]]
. Вам нужно будет вызывать это несколько раз, пока пользователь не выберет один из пунктов меню.
Использование nextEventMatchingMask: NSRightMouseUpMask
не будет работать во всех или даже в большинстве случаев. Если пользователь щелкнет правой кнопкой мыши на элементе управления, правая кнопка мыши сразу же поднимется после его выключения без выбора пункта меню, и выбор пункта меню, вероятно, (хотя и не обязательно) произойдет через левая кнопка мыши. Лучше просто повторять цикл выполнения, пока пользователь не выберет что-либо или не закроет меню.
Я не знаю, как сказать, что пользователь закрыл меню, ничего не выбрав.