Есть ли в Какао эквивалентный метод для синхронного TrackPopupMenu в Windows?

StackOverflow https://stackoverflow.com/questions/227935

  •  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 не будет работать во всех или даже в большинстве случаев. Если пользователь щелкнет правой кнопкой мыши на элементе управления, правая кнопка мыши сразу же поднимется после его выключения без выбора пункта меню, и выбор пункта меню, вероятно, (хотя и не обязательно) произойдет через левая кнопка мыши. Лучше просто повторять цикл выполнения, пока пользователь не выберет что-либо или не закроет меню.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top