Есть ли в Какао эквивалентный метод для синхронного TrackPopupMenu в Windows? - PullRequest
0 голосов
/ 23 октября 2008

В ответ на событие rightMouse я хочу вызвать функцию, которая отображает контекстное меню, запускает его и отвечает на выбранный пункт меню. В Windows я могу использовать TrackPopupMenu с флагом TPM_RETURNCMD.

Какой самый простой способ реализовать это в Какао? Кажется, NSMenu: popUpContextMenu хочет опубликовать событие в указанном NSView. Должен ли я создать фиктивный вид и дождаться события, прежде чем вернуться? Если да, то как мне «подождать» или сбросить события, если я не вернусь на свою главную страницу?

Ответы [ 3 ]

2 голосов
/ 23 октября 2008

«Правильный» способ сделать это в Какао - заставить целевой элемент меню и действие выполнить требуемый метод. Однако, если вы должны сделать это во время вашего первоначального вызова, вы можете использовать [NSView nextEventMatchingMask:] для непрерывного получения новых событий, которые вас интересуют, обрабатывают их и выполняют цикл. Вот пример, который просто ждет, пока не будет отпущена правая кнопка мыши. Возможно, вы захотите использовать более сложный аргумент маски и постоянно вызывать [NSView nextEventMatchingMask:], пока не получите то, что хотите.

NSEvent *localEvent = [[self window] nextEventMatchingMask: NSRightMouseUpMask];

Я думаю, вы найдете «правильный» способ пойти намного проще.

1 голос
/ 23 октября 2008

Похоже, что 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;
    }
 }
0 голосов
/ 23 октября 2008

Прямого эквивалента не существует, кроме как в Carbon, который не рекомендуется.

Для определения правого щелчка следуйте этим инструкциям . Они гарантируют, что вы будете правильно определять щелчки правой кнопкой мыши и удерживать их правой кнопкой мыши, а также отображать меню, когда должны, и не отображать его, когда не должны.

Для следующих событий вы можете попробовать [[NSRunLoop currentRunLoop] runMode:NSEventTrackingRunLoopMode untilDate:[NSDate distantFuture]]. Вам нужно будет вызывать это несколько раз, пока пользователь не выберет один из пунктов меню.

Использование nextEventMatchingMask:NSRightMouseUpMask не будет работать во всех или даже в большинстве случаев. Если пользователь нажимает правой кнопкой мыши на элементе управления , правая кнопка мыши поднимается сразу после его нажатия, без выбора пункта меню, и выбор пункта меню, вероятно, (хотя и не обязательно) произойдет через левую кнопку мыши. Лучше просто повторять цикл выполнения, пока пользователь не выберет что-либо или не закроет меню.

Я не знаю, как сказать, что пользователь закрыл меню, ничего не выбрав.

...