2014-11-14 72 views
9

我在Swift中編寫了一個簡單的狀態欄應用程序,並嘗試使用OS X 10.10中引入的新的NSStatusItem API。Swift:10.10中的NSStatusItem菜單行爲(例如,僅在右鍵單擊時顯示)

我打算的接口是一個簡單的鼠標左鍵單擊statusItem來打開和關閉核心功能,用鼠標右鍵單擊(或按住Control鍵單擊)選項以顯示設置菜單。我不需要爲此功能定製視圖或彈出窗口。

默認情況下,如果NSMenu分配給NSStatusItem,它將在左右兩側單擊顯示菜單。我想改變行爲只顯示菜單右鍵單擊,或者作爲解決方法,防止菜單彈出左鍵單擊

以前,似乎要控制NSStatusItem上的鼠標事件,必須使用重寫的鼠標事件設置自定義視圖(請參閱this related question)。

在10.10中引入的新NSStatusItem API中,設置自定義視圖的方法已被棄用,並且看起來不鼓勵這種行爲。根據@Taylor的this answer,一些不贊成使用的行爲應該通過statusItemObject.button()返回的NSStatusBarButton對象來使用,但是在編寫時沒有NSStatusBarButton的文檔,返回的對象是隻讀的,不能被帶有重寫的鼠標事件處理程序的自定義按鈕。

有沒有辦法讓一些控制級別的鼠標事件是否顯示附加到NSStatusItem(或NSStatusBarButton)的NSMenu?

回答

5

這是我想出了一個解決方案。它工作得很好,但有一件事我不滿意:在右鍵菜單中選擇一個選項後,狀態項保持高亮顯示。只要你與別的東西互動,突出點就會消失。

另請注意,popUpStatusItemMenu:自OS X 10.10(優勝美地)起「軟性棄用」,並將在未來版本中正式棄用。目前,它的工作原理並不會給你任何警告。希望我們在得到正式棄用之前有一個完全支持的方式來做到這一點 - 如果您同意,我建議您使用filing a bug report

首先,您需要一些屬性和枚舉:

typedef NS_ENUM(NSUInteger,JUNStatusItemActionType) { 
    JUNStatusItemActionNone, 
    JUNStatusItemActionPrimary, 
    JUNStatusItemActionSecondary 
}; 

@property (nonatomic, strong) NSStatusItem *statusItem; 
@property (nonatomic, strong) NSMenu *statusItemMenu; 
@property (nonatomic) JUNStatusItemActionType statusItemAction; 

然後在某個時候,你會想設置的狀態項:

NSStatusItem *item = [[NSStatusBar systemStatusBar] statusItemWithLength:29.0]; 
NSStatusBarButton *button = item.button; 
button.image = [NSImage imageNamed:@"Menu-Icon"]; 
button.target = self; 
button.action = @selector(handleStatusItemAction:); 
[button sendActionOn:(NSLeftMouseDownMask|NSRightMouseDownMask|NSLeftMouseUpMask|NSRightMouseUpMask)]; 
self.statusItem = item; 

然後你只需要處理由狀態項按鈕發送的動作:

- (void)handleStatusItemAction:(id)sender { 

    const NSUInteger buttonMask = [NSEvent pressedMouseButtons]; 
    BOOL primaryDown = ((buttonMask & (1 << 0)) != 0); 
    BOOL secondaryDown = ((buttonMask & (1 << 1)) != 0); 
    // Treat a control-click as a secondary click 
    if (primaryDown && ([NSEvent modifierFlags] & NSControlKeyMask)) { 
     primaryDown = NO; 
     secondaryDown = YES; 
    } 

    if (primaryDown) { 
     self.statusItemAction = JUNStatusItemActionPrimary; 
    } else if (secondaryDown) { 
     self.statusItemAction = JUNStatusItemActionSecondary; 
     if (self.statusItemMenu == nil) { 
      NSMenu *menu = [[NSMenu alloc] initWithTitle:@""]; 
      [menu addItemWithTitle:NSLocalizedString(@"Quit",nil) action:@selector(terminate:) keyEquivalent:@""]; 
      self.statusItemMenu = menu; 
     } 
     [self.statusItem popUpStatusItemMenu:self.statusItemMenu]; 
    } else { 
     self.statusItemAction = JUNStatusItemActionNone; 
     if (self.statusItemAction == JUNStatusItemActionPrimary) { 
      // TODO: add whatever you like for the primary action here 
     } 
    } 

} 

所以基本上,handleStatusItemAction:被調用鼠標放下並鼠標移動鼠標按鈕。當一個按鈕關閉時,它會跟蹤它是否應該執行主要操作或次要操作。如果是次要操作,則立即處理,因爲菜單通常出現在鼠標下方。如果這是主要操作,則在鼠標上處理。

+1

幾個筆記(以下片段在Swift中): a)通過爲StatusItem對象設置'item.highlightMode = false',可以解決右鍵單擊後剩下的高亮部分。 b)主動作的情況應該首先在最後的else塊(在'self.statusItemAction = JUNStatusItemActionNone;'之前)以使所需的行爲起作用。否則,您正在設置'self.statusItemAction'的值,然後立即檢查它是否有所不同。 – AmusedToDeath

0

這棄用10.10,但會繼續努力:

[self.statusItem setTarget:self]; // Otherwise this goes to the first responder 
[self.statusItem setAction:@selector(statusItemClicked:)]; 
[self.statusItem sendActionOn:(NSRightMouseUpMask)]; 

您可以通過bitmasking它們設置在setActionOn其他事件。因此,舉例來說,如果你想左,右鍵:

[self.statusItem sendActionOn:(NSLeftMouseUpMask | NSRightMouseUpMask)]; 

(請原諒,objC,你應該能夠把它翻譯成快捷,它應該工作)

相關問題