2012-06-26 15 views
6

Çok nadir kullanılan uygulamanın ana menüsüne bir menü öğesi eklemek istiyorum. Varsayılan olarak gizlenmesini ve yalnızca kullanıcı Seçenek tuşu basılı tutulduğunda göstermesini istiyorum. Bunu nasıl yaparım?Seçenek tuşuna basarak uygulamanın ana menüsünde menü öğesini gizle/göster tuşu

Ben flagsChanged: işlemek gerektiğini görünüyor, ama NSResponder 'ın yöntemdir ve NSMenuNSResponder devraldığı etmiyor? Ana pencere denetleyicide denedim ve menüyü tıklatmadan önce Option tuşuna bastığımda çalışır. Aşağıdaki kullanım durumu çalışmıyor: menü maddesine tıklayın (öğe yok), seçenek tuşuna basın - öğem görünmeli, seçenek tuşunu bırakın - öğe kaybolacaktır.

Ben de NSEvent en addLocalMonitorForEventsMatchingMask:handler: ve NSFlagsChangedMask için addGlobalMonitorForEventsMatchingMask:handler: çalıştı ama ettik ana menü açık ne yerel veya global işleyicileri ateş değilken seçenek tuşuna basıldığında.

Bunu nasıl yapabilirim?

cevap

5

Aşağıdakileri applicationDidFinishLaunching öğesine ekleyin. Bir performans isabet çok fazla değil bu yüzden denetimleri izlenen edilirken

// Dynamically update QCServer menu when option key is pressed 
NSMenu *submenu = [[[NSApp mainMenu] itemWithTitle:@"QCServer"] submenu];  
NSTimer *t = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(updateMenu:) userInfo:submenu repeats:YES]; 
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSEventTrackingRunLoopMode]; 

sonra

- (void)updateMenu:(NSTimer *)t { 

    static NSMenuItem *menuItem = nil; 
    static BOOL isShowing = YES; 

    // Get global modifier key flag, [[NSApp currentEvent] modifierFlags] doesn't update while menus are down 
    CGEventRef event = CGEventCreate (NULL); 
    CGEventFlags flags = CGEventGetFlags (event); 
    BOOL optionKeyIsPressed = (flags & kCGEventFlagMaskAlternate) == kCGEventFlagMaskAlternate; 
    CFRelease(event); 

    NSMenu *menu = [t userInfo]; 

    if (!menuItem) { 
     // View Batch Jobs... 
     menuItem = [menu itemAtIndex:6]; 
     [menuItem retain]; 
    } 

    if (!isShowing && optionKeyIsPressed) { 
     [menu insertItem:menuItem atIndex:6]; 
     [menuItem setEnabled:YES]; 
     isShowing = YES; 
    } else if (isShowing && !optionKeyIsPressed) { 
     [menu removeItem:menuItem]; 
     isShowing = NO; 
    } 

    NSLog(@"optionKeyIsPressed %d", optionKeyIsPressed); 
} 

zamanlayıcı sadece yangınları ekleyin.

+0

Sadece denemek için zamanım vardı ve işe yarıyor. Çok teşekkürler! –

9

Menüyü oluştururken isteğe bağlı öğeyi dahil edin ve onu gizli olarak işaretleyin. Daha sonra, sınıf örneğinizi menü delegesi olarak ayarlayın ve menü isteğe bağlı öğenin gizli durumunu kontrol etmek için açıkken bir çalışma döngüsü gözlemcisi ekleyin. NSMenuDelegate yöntemle menuNeedsUpdate: yana

@implementation AppController { 
    CFRunLoopObserverRef _menuObserver; 
} 

- (void)updateMenu { 
    BOOL hideOptionalMenuItems = ([NSEvent modifierFlags] & NSAlternateKeyMask) != NSAlternateKeyMask; 
    [self.optionalMenuItem setHidden:hideOptionalMenuItems]; 
} 

- (void)menuWillOpen:(NSMenu *)menu { 
    [self updateMenu]; 

    if (_menuObserver == NULL) { 
     _menuObserver = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { 
      [self updateMenu]; 
     }); 

     CFRunLoopAddObserver(CFRunLoopGetCurrent(), _menuObserver, kCFRunLoopCommonModes); 
    } 
} 

- (void)menuDidClose:(NSMenu *)menu { 
    if (_menuObserver != NULL) { 
     CFRunLoopObserverInvalidate(_menuObserver); 
     CFRelease(_menuObserver); 
     _menuObserver = NULL; 
    } 
} 
+0

Bu daha iyi bir çözüm gibi görünüyor, biraz sonra deneyeceğim. Teşekkürler. –

+0

Bu bir şampiyon gibi çalıştı. – dbainbridge

+1

Dikkatli olun. Ben sadece bunu denedim ve bir menü ve menü menülerinde farenizi diğer menüler açmak için hareket ettirdiğinizde, menuNeedsUpdate: her zaman çağrılmıyor (menü açıksa), bir kazaya yol açıyor. MenuNeedsUpdate yerine 'menuWillOpen:' kullanın: ' – Mark

1

gösterilmeden önce denir, bu [NSEvent modifierFlags] alternatif bitine sahiptir olmadığını kontrol bunu geçersiz ve/göstermek gizli menü öğelerini gizlemek için bu kullanmak mümkündür. İşte

tam olarak bu konuyu kapsayan, Reveal Functionality with Key Modifiers kopyalanmış, bir örnek: Bu iki menü öğelerini kullanmaktır elde edebilirsiniz

#pragma NSMenu delegate methods 

- (void) menuNeedsUpdate: (NSMenu *)menu 
{ 
    NSLog(@"menuNeedsUpdate: %@", menu); 

    NSUInteger flags = ([NSEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask); 

    // We negate the value below because, if flags == NSAlternateKeyMask is TRUE, that 
    // means the user has the Option key held, and wants to see the secret menu, so we 
    // need shoudHideSecretMenu to be FALSE, so we just negate the value. 
    BOOL shoudHideSecretMenu = !(flags == NSAlternateKeyMask); 

    NSLog(@"Flags: 0x%lx (0x%x), shoudHideSecretMenu = %d", flags, NSAlternateKeyMask, shoudHideSecretMenu); 

    [secretMenuItem setHidden:shoudHideSecretMenu]; 
} 
+0

Denemedim, ancak bu yöntem gizli menü öğesini yalnızca Cmd tuşunun menüyü açmadan önce basması durumunda gösterecektir. Ama menü hala açıkken cmd tuşuna basarak/bırakarak bu menü öğesini göstermek/gizlemek istiyorum. –

10

iyi yolu, ilk menü öğesi yüksekliği 0 özel bir görünümüne kullanır ve devre dışı bırakılmış, hemen altında bir "alternatif" maddedir. (Bu öğenin keyEquivalentModifierMask değerini NSAlternateKeyMask olarak ayarlamalısınız) Bu düzenleme ile, seçenek tuşuna bastığınızda, NSMenu otomatik olarak sıfır yükseklikteki menü öğesini manüel olarak bir menü öğesi oluşturma etkisine sahip olacak alternatif öğe ile değiştirir.

Zamanlayıcılar, güncelleştirmeler veya bayrak değişikliği bildirimlerine gerek yoktur.

Bu işlevsellik burada belgelerinde açıklanmıştır: Managing Alternates

+0

"0 yüksekliğinde özel bir görünüm kullanıyor ve devre dışı" - Bir örnek güzel olurdu. – frakman1

+0

Özel görünüm kullanmanıza gerek yok. Sadece çalışır (MacOS 11.6'da test edilmiştir). –

+0

Bu işe yarayabilir, ancak Erişilebilirlik ve kullanıcı için hangi menü öğelerini kullanabileceğine yönelik diğer tüm mekanizmalar üzerinde gerçekten kötüdür. İşletim sisteminden NSMenuItem'inizin durumunu gizlemek istemezsiniz (başka bir deyişle - gerçekten gizler). –

0

burada bazı karmaşık cevaplar var ama aslında çok basit:

2 menuitems oluşturun. Birincisi, istediğiniz keyEquivalent ve title ile varsayılandır. İkincisi, değiştirici tuşu aşağıdayken gösterilecek olan şeydir - yine ayrı keyEquivalent ve title ile. İkinci menüde 'Alternatif' seçeneğini etkinleştirin ve diğer her şey otomatik olarak gerçekleşir.

Gerekli değiştirici, 2 keyEquivalent değeri karşılaştırılarak algılanır.