如何为NSToolBarItem默认视图添加提示框并动态显示撤销/重做动作?
解决NSToolBarItem撤销/重做按钮动态提示框问题
核心需求梳理
- 使用默认
NSToolBarItem实现撤销/重做功能,希望提示框(tooltip)动态显示当前可执行的撤销/重做动作名称 - 不想自定义视图,希望保留系统默认的
NSButton私有子类特性 - 不确定何时更新
toolTip属性,也不清楚如何访问默认视图
解决方案一:监听撤销管理器状态,动态更新ToolTip
无需操作视图,直接通过监听NSUndoManager的动作名称变化,同步更新NSToolBarItem的toolTip属性即可——系统会自动将NSToolBarItem的toolTip同步到其对应的默认视图上。
实现步骤
- 添加KVO监听:监听
NSUndoManager的undoActionName和redoActionName属性,这两个属性会随撤销栈的变化自动更新 - 更新ToolTip:在监听回调中根据最新的动作名称设置对应工具栏项的提示文本
- 移除监听:在对象销毁时清理KVO监听,避免内存泄漏
代码示例(Swift)
// 假设undoManager是当前对象的属性,undoToolBarItem、redoToolBarItem是对应的工具栏项 override func viewDidLoad() { super.viewDidLoad() // 添加KVO监听 undoManager?.addObserver(self, forKeyPath: "undoActionName", options: [.initial, .new], context: nil) undoManager?.addObserver(self, forKeyPath: "redoActionName", options: [.initial, .new], context: nil) } override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { guard let undoManager = object as? NSUndoManager else { return } switch keyPath { case "undoActionName": let tip = undoManager.undoActionName.isEmpty ? "撤销" : "撤销:\(undoManager.undoActionName)" undoToolBarItem.toolTip = tip case "redoActionName": let tip = undoManager.redoActionName.isEmpty ? "重做" : "重做:\(undoManager.redoActionName)" redoToolBarItem.toolTip = tip default: super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) } } deinit { undoManager?.removeObserver(self, forKeyPath: "undoActionName") undoManager?.removeObserver(self, forKeyPath: "redoActionName") }
解决方案二:访问默认视图(如果需要直接操作视图)
如果必须对默认视图进行额外操作(比如自定义提示框矩形),可以通过以下方式获取系统默认的NSButton子类视图:
方法1:通过工具栏代理回调获取
在NSToolbarDelegate的toolbarDidAddItem方法中,工具栏项添加完成后即可拿到其对应的视图:
func toolbarDidAddItem(_ notification: Notification) { guard let item = notification.userInfo?[NSToolbarItemNotificationItemKey] as? NSToolbarItem else { return } if item.itemIdentifier == .undo { if let defaultButton = item.view as? NSButton { // 在这里操作默认按钮视图,比如设置自定义提示框相关属性 } } }
方法2:KVO监听工具栏项的view属性
监听NSToolBarItem的view属性,当视图被系统实例化后立即获取:
// 初始化工具栏项后添加监听 undoToolBarItem.addObserver(self, forKeyPath: "view", options: .new, context: nil) // 监听回调 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { if keyPath == "view", let button = change?[.newKey] as? NSButton, object as? NSToolBarItem === undoToolBarItem { // 操作默认按钮视图 undoToolBarItem.removeObserver(self, forKeyPath: "view") // 获取后移除监听,避免重复回调 } else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) } }
内容的提问来源于stack exchange,提问作者jeanlain
相关产品推荐
相关产品推荐

