Domanda

In risposta a un evento rightMouse, desidero chiamare una funzione che visualizza un menu di scelta rapida, lo esegue e risponde alla voce di menu selezionata. In Windows posso usare TrackPopupMenu con il flag TPM_RETURNCMD.

Qual è il modo più semplice per implementarlo in Cocoa? Sembra NSMenu: popUpContextMenu vuole pubblicare un evento nel NSView specificato. Devo creare una vista fittizia e attendere l'evento prima di tornare? In tal caso, come posso "attendere" o scaricare eventi dato che non torno al mio principale?

È stato utile?

Soluzione 2

Sembra che popUpContextMenu sia già sincrono. Dato che non vedevo un modo per usare NSMenu senza che fosse necessario inviare una notifica a un NSView, mi è venuto in mente uno schema che crea un'istanza di un NSView temporaneo. L'obiettivo è visualizzare un menu popup e restituire l'elemento selezionato nel contesto di una singola chiamata di funzione. Di seguito sono riportati frammenti di codice della mia soluzione 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;
    }
 }

Altri suggerimenti

Il modo "corretto" per eseguire questa operazione in Cocoa consiste nel fare in modo che l'obiettivo e l'azione della voce di menu eseguano il metodo richiesto. Tuttavia, se è necessario farlo durante la chiamata iniziale, è possibile utilizzare [NSView nextEventMatchingMask:] per recuperare continuamente nuovi eventi che ti interessano, gestirli e eseguire il loop. Ecco un esempio che attende solo il rilascio del pulsante destro del mouse. Probabilmente vorrai utilizzare un argomento maschera più complesso e chiamare continuamente [NSView nextEventMatchingMask:] fino a ottenere ciò che desideri.

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

Penso che troverai il modo "corretto" per andare molto più facilmente.

Non esiste un equivalente diretto, tranne in Carbon, che è deprecato.

Per rilevare il clic con il tasto destro, seguire queste istruzioni . Assicurano che rileverai correttamente i clic con il tasto destro e quelli a destra e visualizzerai il menu quando dovresti e non visualizzarlo quando non dovresti.

Per i seguenti eventi, puoi provare [[NSRunLoop currentRunLoop] runMode: NSEventTrackingRunLoopMode fino alla data: [NSDate distanceFuture]] . Dovrai chiamarlo ripetutamente fino a quando l'utente non avrà scelto una delle voci di menu.

L'uso di nextEventMatchingMask: NSRightMouseUpMask non funzionerà in tutti o persino nella maggior parte dei casi. Se l'utente fa clic con il pulsante destro del mouse su sul controllo, il pulsante destro del mouse salirà immediatamente dopo la discesa, senza selezionare una voce di menu e la selezione delle voci di menu probabilmente (sebbene non necessariamente) avverrà attraverso il tasto sinistro del mouse. Meglio semplicemente eseguire il ciclo di esecuzione ripetutamente fino a quando l'utente non seleziona qualcosa o chiude il menu.

Non so come dire che l'utente ha chiuso il menu senza selezionare nulla.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top