Mac開發(fā)基礎(chǔ)23-NSMenu
NSMenu 是 macOS 應(yīng)用中的一個重要控件,用于創(chuàng)建應(yīng)用程序的菜單。這些菜單通常出現(xiàn)在屏幕頂部的菜單欄中,但也可以作為上下文菜單出現(xiàn)。NSMenu 和 NSMenuItem 協(xié)同工作,NSMenu 是菜單容器,而 NSMenuItem 是菜單項。本指南將詳細(xì)介紹 NSMenu 的常見 API 和基礎(chǔ)技巧。
基本使用
創(chuàng)建和初始化
Objective-C
#import <Cocoa/Cocoa.h>
// 創(chuàng)建一個 NSMenu 實例
NSMenu *menu = [[NSMenu alloc] initWithTitle:@"Main Menu"];
Swift
import Cocoa
// 創(chuàng)建一個 NSMenu 實例
let menu = NSMenu(title: "Main Menu")
創(chuàng)建菜單項
Objective-C
// 創(chuàng)建菜單項
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:@"First Item"
action:@selector(handleMenuAction:)
keyEquivalent:@"1"];
// 設(shè)置菜單項的目標(biāo)對象
[menuItem setTarget:self];
// 將菜單項添加到菜單
[menu addItem:menuItem];
Swift
// 創(chuàng)建菜單項
let menuItem = NSMenuItem(title: "First Item",
action: #selector(handleMenuAction(_:)),
keyEquivalent: "1")
// 設(shè)置菜單項的目標(biāo)對象
menuItem.target = self
// 將菜單項添加到菜單
menu.addItem(menuItem)
響應(yīng)菜單項選擇
Objective-C
// 實現(xiàn)菜單項選擇的響應(yīng)方法
- (void)handleMenuAction:(id)sender {
NSMenuItem *selectedItem = (NSMenuItem *)sender;
NSLog(@"Selected item: %@", selectedItem.title);
}
Swift
// 實現(xiàn)菜單項選擇的響應(yīng)方法
@objc func handleMenuAction(_ sender: Any?) {
if let menuItem = sender as? NSMenuItem {
print("Selected item: \(menuItem.title)")
}
}
創(chuàng)建帶有子菜單的菜單項
Objective-C
// 創(chuàng)建子菜單
NSMenu *subMenu = [[NSMenu alloc] initWithTitle:@"Sub Menu"];
// 創(chuàng)建子菜單項
NSMenuItem *subMenuItem = [[NSMenuItem alloc] initWithTitle:@"Sub Item"
action:@selector(handleSubMenuAction:)
keyEquivalent:@""];
[subMenuItem setTarget:self];
[subMenu addItem:subMenuItem];
// 創(chuàng)建帶有子菜單的菜單項
NSMenuItem *mainMenuItem = [[NSMenuItem alloc] initWithTitle:@"Main Item"
action:NULL
keyEquivalent:@""];
[menu addItem:mainMenuItem];
[menu setSubmenu:subMenu forItem:mainMenuItem];
Swift
// 創(chuàng)建子菜單
let subMenu = NSMenu(title: "Sub Menu")
// 創(chuàng)建子菜單項
let subMenuItem = NSMenuItem(title: "Sub Item", action: #selector(handleSubMenuAction(_:)), keyEquivalent: "")
subMenuItem.target = self
subMenu.addItem(subMenuItem)
// 創(chuàng)建帶有子菜單的菜單項
let mainMenuItem = NSMenuItem(title: "Main Item", action: nil, keyEquivalent: "")
menu.addItem(mainMenuItem)
menu.setSubmenu(subMenu, for: mainMenuItem)
動態(tài)更新菜單項
Objective-C
// 更新菜單項狀態(tài)
- (void)updateMenuItems {
NSMenuItem *menuItem = [menu itemWithTitle:@"First Item"];
if (menuItem) {
[menuItem setState:NSControlStateValueOn]; // 或者使用 NSControlStateValueOff
}
}
Swift
// 更新菜單項狀態(tài)
func updateMenuItems() {
if let menuItem = menu.item(withTitle: "First Item") {
menuItem.state = .on // 或者使用 .off
}
}
使用委托
NSMenuDelegate 可以幫助處理菜單的顯示和隱藏等事件。
Objective-C
// 設(shè)置代理
[menu setDelegate:self];
// 實現(xiàn)代理方法,處理菜單將顯示事件
- (void)menuWillOpen:(NSMenu *)menu {
NSLog(@"Menu will open");
}
// 實現(xiàn)代理方法,處理菜單將隱藏事件
- (void)menuDidClose:(NSMenu *)menu {
NSLog(@"Menu did close");
}
Swift
// 設(shè)置代理
menu.delegate = self
// 實現(xiàn)代理方法,處理菜單將顯示事件
func menuWillOpen(_ menu: NSMenu) {
print("Menu will open")
}
// 實現(xiàn)代理方法,處理菜單將隱藏事件
func menuDidClose(_ menu: NSMenu) {
print("Menu did close")
}
高級用法
動態(tài)生成菜單項
Objective-C
// 動態(tài)生成菜單項
- (void)generateDynamicMenuItems {
NSArray *items = @[@"Dynamic Item 1", @"Dynamic Item 2", @"Dynamic Item 3"];
for (NSString *itemTitle in items) {
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:itemTitle
action:@selector(handleDynamicMenuAction:)
keyEquivalent:@""];
[menuItem setTarget:self];
[menu addItem:menuItem];
}
}
Swift
// 動態(tài)生成菜單項
func generateDynamicMenuItems() {
let items = ["Dynamic Item 1", "Dynamic Item 2", "Dynamic Item 3"]
for itemTitle in items {
let menuItem = NSMenuItem(title: itemTitle, action: #selector(handleDynamicMenuAction(_:)), keyEquivalent: "")
menuItem.target = self
menu.addItem(menuItem)
}
}
上下文菜單
創(chuàng)建右鍵上下文菜單是 NSMenu 的常見用法。
Objective-C
// 創(chuàng)建上下文菜單
NSMenu *contextMenu = [[NSMenu alloc] initWithTitle:@"Context Menu"];
NSMenuItem *contextMenuItem = [[NSMenuItem alloc] initWithTitle:@"Context Item"
action:@selector(handleContextMenuAction:)
keyEquivalent:@""];
[contextMenuItem setTarget:self];
[contextMenu addItem:contextMenuItem];
// 設(shè)置視圖的上下文菜單
[someView setMenu:contextMenu];
Swift
// 創(chuàng)建上下文菜單
let contextMenu = NSMenu(title: "Context Menu")
let contextMenuItem = NSMenuItem(title: "Context Item", action: #selector(handleContextMenuAction(_:)), keyEquivalent: "")
contextMenuItem.target = self
contextMenu.addItem(contextMenuItem)
// 設(shè)置視圖的上下文菜單
someView.menu = contextMenu
禁用或啟用菜單項
Objective-C
// 禁用菜單項
- (void)disableMenuItem {
NSMenuItem *menuItem = [menu itemWithTitle:@"First Item"];
[menuItem setEnabled:NO]; // 設(shè)置菜單項為禁用狀態(tài)
}
// 啟用菜單項
- (void)enableMenuItem {
NSMenuItem *menuItem = [menu itemWithTitle:@"First Item"];
[menuItem setEnabled:YES]; // 設(shè)置菜單項為啟用狀態(tài)
}
Swift
// 禁用菜單項
func disableMenuItem() {
if let menuItem = menu.item(withTitle: "First Item") {
menuItem.isEnabled = false // 設(shè)置菜單項為禁用狀態(tài)
}
}
// 啟用菜單項
func enableMenuItem() {
if let menuItem = menu.item(withTitle: "First Item") {
menuItem.isEnabled = true // 設(shè)置菜單項為啟用狀態(tài)
}
}
自動更新菜單項狀態(tài)
通過實現(xiàn) NSMenuDelegate 的 menu:updateItem:atIndex:shouldCancel: 方法,可以自動更新菜單項狀態(tài)。
Objective-C
// 設(shè)置代理
[menu setDelegate:self];
// 實現(xiàn)代理方法,自動更新菜單項狀態(tài)
- (BOOL)menu:(NSMenu *)menu updateItem:(NSMenuItem *)item atIndex:(NSInteger)index shouldCancel:(BOOL)shouldCancel {
item.state = (index % 2 == 0) ? NSControlStateValueOn : NSControlStateValueOff;
return YES;
}
Swift
// 設(shè)置代理
menu.delegate = self
// 實現(xiàn)代理方法,自動更新菜單項狀態(tài)
func menu(_ menu: NSMenu, update item: NSMenuItem, at index: Int, shouldCancel: Bool) -> Bool {
item.state = (index % 2 == 0) ? .on : .off
return true
}
封裝工具類
為了更方便地使用 NSMenu,可以封裝一個工具類,提供常見功能的高層接口。
Objective-C
#import <Cocoa/Cocoa.h>
@interface NSMenuHelper : NSObject
+ (NSMenu *)createMenuWithTitle:(NSString *)title items:(NSArray<NSDictionary<NSString *, NSString *> *> *)items target:(id)target;
+ (void)addItemWithTitle:(NSString *)title action:(SEL)action toMenu:(NSMenu *)menu target:(id)target;
+ (void)addSubMenuWithTitle:(NSString *)title toMenu:(NSMenu *)menu subMenu:(NSMenu *)subMenu;
@end
@implementation NSMenuHelper
+ (NSMenu *)createMenuWithTitle:(NSString *)title items:(NSArray<NSDictionary<NSString *, NSString *> *> *)items target:(id)target {
NSMenu *menu = [[NSMenu alloc] initWithTitle:title];
for (NSDictionary<NSString *, NSString *> *item in items) {
NSString *title = item.allKeys.firstObject;
SEL action = NSSelectorFromString(item.allValues.firstObject);
[NSMenuHelper addItemWithTitle:title action:action toMenu:menu target:target];
}
return menu;
}
+ (void)addItemWithTitle:(NSString *)title action:(SEL)action toMenu:(NSMenu *)menu target:(id)target {
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:title action:action keyEquivalent:@""];
[menuItem setTarget:target];
[menu addItem:menuItem];
}
+ (void)addSubMenuWithTitle:(NSString *)title toMenu:(NSMenu *)menu subMenu:(NSMenu *)subMenu {
NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:title action:nil keyEquivalent:@""];
[menu addItem:menuItem];
[menu setSubmenu:subMenu forItem:menuItem];
}
@end
Swift
import Cocoa
class NSMenuHelper {
// 創(chuàng)建 Menu 并初始化菜單項
static func createMenu(title: String, items: [String: Selector], target: AnyObject) -> NSMenu {
let menu = NSMenu(title: title)
for (title, action) in items {
addItem(withTitle: title, action: action, to: menu, target: target)
}
return menu
}
// 添加菜單項
static func addItem(withTitle title: String, action: Selector, to menu: NSMenu, target: AnyObject) {
let menuItem = NSMenuItem(title: title, action: action, keyEquivalent: "")
menuItem.target = target
menu.addItem(menuItem)
}
// 添加子菜單
static func addSubMenu(withTitle title: String, to menu: NSMenu, subMenu: NSMenu) {
let menuItem = NSMenuItem(title: title, action: nil, keyEquivalent: "")
menu.addItem(menuItem)
menu.setSubmenu(subMenu, for: menuItem)
}
}
使用示例
Objective-C
// 創(chuàng)建 Menu
NSArray *items = @[
@{@"First Item": NSStringFromSelector(@selector(handleMenuAction:))},
@{@"Second Item": NSStringFromSelector(@selector(handleMenuAction:))}
];
NSMenu *menu = [NSMenuHelper createMenuWithTitle:@"Main Menu" items:items target:self];
// 創(chuàng)建子菜單
NSMenu *subMenu = [NSMenuHelper createMenuWithTitle:@"Sub Menu" items:@{@{@"Sub Item": NSStringFromSelector(@selector(handleSubMenuAction:))}} target:self];
[NSMenuHelper addSubMenuWithTitle:@"Main Item with SubMenu" toMenu:menu subMenu:subMenu];
Swift
// 創(chuàng)建 Menu
let items: [String: Selector] = [
"First Item": #selector(handleMenuAction(_:)),
"Second Item": #selector(handleMenuAction(_:))
]
let menu = NSMenuHelper.createMenu(title: "Main Menu", items: items, target: self)
// 創(chuàng)建子菜單
let subMenuItems: [String: Selector] = [
"Sub Item": #selector(handleSubMenuAction(_:))
]
let subMenu = NSMenuHelper.createMenu(title: "Sub Menu", items: subMenuItems, target: self)
NSMenuHelper.addSubMenu(withTitle: "Main Item with SubMenu", to: menu, subMenu: subMenu)
總結(jié)
通過了解 NSMenu 的基本使用、創(chuàng)建菜單項、響應(yīng)菜單項選擇、創(chuàng)建子菜單、動態(tài)更新菜單項、使用上下文菜單等高級用法,以及封裝工具類,你將能夠更高效地使用 NSMenu 創(chuàng)建復(fù)雜的菜單系統(tǒng)。在實際應(yīng)用中,合理使用這些技巧可以顯著提升用戶界面的靈活性和用戶體驗。。
將來的你會感謝今天如此努力的你!
版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。

浙公網(wǎng)安備 33010602011771號