【问题标题】:How do I detect if an NSMenu is closed?如何检测 NSMenu 是否已关闭?
【发布时间】:2021-07-10 00:43:03
【问题描述】:

我从这个兔子洞开始,因为一个 SwiftUI 按钮,被指定用于弹出一个菜单,.buttonStyle(BorderlessButtonStyle()) 样式在从浅色模式切换到深色模式时行为不正确。

很沮丧,我决定自己做一个按钮。我注意到 SwiftUI 按钮在弹出菜单时会发生某种切换,所以我也希望我的按钮也有这种行为。因此,我需要找出 NSMenu 何时关闭。

我已经尝试了here ⤵︎建议的答案

class NSMenuDelegateModified: NSObject, NSMenuDelegate, ObservableObject {

    var menu: NSMenu

    @Published var isVisible: Bool?

    internal init(menu: NSMenu) {
        self.menu = menu
        super.init()
        self.menu.delegate = self
    }

    func menuDidClose(_ menu: NSMenu) {
        isVisible = false
    }

    func menuWillOpen(_ menu: NSMenu) {
        isVisible = true
    }
}

现在这将告诉我菜单是否在类中可见,但是当我尝试在类的实例化对象上打印出 .isVisible 时,它只返回 false。

有没有办法解决这个问题?

【问题讨论】:

    标签: swift macos swiftui nsmenu


    【解决方案1】:

    所以我明白了为什么我不能在课堂外的.isVisible 中找到true!这是因为我使用menu.popUp(...) 打开我的菜单。

    事实证明,这个函数会暂停应用程序的某些部分或整个主线程(我真的不确定)的执行,直到它可以返回状态⤵︎

    true = user selected something from the menu
    
    false = user hasn't selected anything and the menu closed
    

    您可以在Apple's documentation查看更多详情。


    解决方案

    考虑到这一点,一切都变得容易多了!要切换按钮,我只需在调用 menu.popUp(...) 后更改颜色即可。

    这意味着当菜单弹出时,颜色不会再次改变,直到从函数返回状态并恢复执行!

    更新答案

    看起来我搞砸了功能,而且比我预期的要复杂。这是我在下面得到的结果⤵︎

    .opacity(pressed ? 1 : 0.6)
    .inactiveWindowTap { pressed in
    
        if popped == nil {
    
            // Only register mouse ups
            if !pressed {
                popped = menu.popUp(...)
                // Execution pauses here and waits till a state is returned
            }
    
            self.pressed = pressed
        }
    
        else if !pressed {
            popped = nil
        }
    }
    .whenHovered { hovering in
        if hovering == false, popped != nil {
            popped = nil
        }
    }
    

    这个解决方案非常适合我的需求,所以我希望这里所说的内容仍然可以帮助某人。希望有人能提出比这更好的答案。

    旧答案(这是不正确的,不能按预期工作)

    .opacity(pressed ? 1 : 0.6)
    .inactiveWindowTap { pressed in
    
        // Only register mouse ups
        if !pressed {
            // You can use the bool returned from this function but you don't have to.
            menu.popUp(...) // Execution pauses here until a state is found.
        }
    
        self.pressed = pressed
    }
    

    【讨论】:

    • NSMenu 在主动显示菜单时阻塞了主线程的RunLoop.Mode.default aka NSDefaultRunLoopMode。使用不同的运行循环模式有多种使用方法。
    • 感谢您的洞察!目前,此解决方案有效,但我可以想象在许多其他情况下这将成为问题。
    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2012-08-05
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    相关资源
    最近更新 更多