Existe uma técnica equivalente em cacau para o trackpopupmenu síncrono no Windows?

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

  •  03-07-2019
  •  | 
  •  

Pergunta

Em resposta a um evento RightMouse, quero chamar uma função que exibe um menu de contexto, o executa e responde ao item de menu selecionado. No Windows, posso usar o trackpopupMenu com o sinalizador TPM_RETURNNCMD.

Qual é a maneira mais fácil de implementar isso no cacau? Parece que NSMENU: PopupContextMenu quer postar um evento no NSView especificado. Devo criar uma visão fictícia e esperar o evento antes de retornar? Em caso afirmativo, como faço para "esperar" ou liberar eventos, já que não estou voltando ao meu principal?

Foi útil?

Solução 2

Parece que o PopUpContextMenu já é síncrono. Como não vi uma maneira de usar o NSMENU sem que ele envie uma notificação para uma NSView, criei um esquema que instancia uma NSView temporária. O objetivo é exibir um menu pop -up e retornar o item selecionado no contexto de uma única chamada de função. A seguir, os trechos de código da minha solução proposta:

// 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;
    }
 }

Outras dicas

A maneira 'adequada' de fazer isso no cacau é fazer com que o alvo e a ação do item de menu executem o método necessário. No entanto, se você precisar fazer isso dentro da sua chamada inicial, poderá usar [NSView nextEventMatchingMask:] Para buscar continuamente novos eventos que lhe interessam, lidam com eles e loop. Aqui está um exemplo que apenas espera até que o botão certo do mouse seja lançado. Você provavelmente vai querer usar um argumento de máscara mais complexo e ligar continuamente [NSView nextEventMatchingMask:] até você conseguir o que deseja.

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

Eu acho que você encontrará o caminho 'adequado' para ir muito mais fácil.

Não há equivalente direto, exceto em carbono, que é preterido.

Para detectar o clique com o botão direito, siga estas instruções. Eles garantem que você detecte corretamente o botão direito do mouse e os seguintes e exibirá o menu quando deve e não exibi-lo quando não deve.

Para os seguintes eventos, você pode tentar [[NSRunLoop currentRunLoop] runMode:NSEventTrackingRunLoopMode untilDate:[NSDate distantFuture]]. Você precisará ligar para isso repetidamente até que o usuário tenha escolhido um dos itens do menu.

Usando nextEventMatchingMask:NSRightMouseUpMask Não funcionará no total, ou mesmo na maioria dos casos. Se o usuário corretamente-cliques No seu controle, o botão direito do mouse aumentará imediatamente após o descendo, sem selecionar um item de menu, e a seleção do item de menu provavelmente (embora não necessariamente) acontecerá através do botão esquerdo do mouse. Melhor apenas executar o loop de corrida repetidamente até que o usuário selecione algo ou descarte o menu.

Não sei como dizer que o usuário descartou o menu sem selecionar nada.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top