You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为NSToolBarItem默认视图添加提示框并动态显示撤销/重做动作?

解决NSToolBarItem撤销/重做按钮动态提示框问题

核心需求梳理

  • 使用默认NSToolBarItem实现撤销/重做功能,希望提示框(tooltip)动态显示当前可执行的撤销/重做动作名称
  • 不想自定义视图,希望保留系统默认的NSButton私有子类特性
  • 不确定何时更新toolTip属性,也不清楚如何访问默认视图

解决方案一:监听撤销管理器状态,动态更新ToolTip

无需操作视图,直接通过监听NSUndoManager的动作名称变化,同步更新NSToolBarItem的toolTip属性即可——系统会自动将NSToolBarItem的toolTip同步到其对应的默认视图上。

实现步骤

  1. 添加KVO监听:监听NSUndoManager的undoActionName和redoActionName属性,这两个属性会随撤销栈的变化自动更新
  2. 更新ToolTip:在监听回调中根据最新的动作名称设置对应工具栏项的提示文本
  3. 移除监听:在对象销毁时清理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 10:44:59