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

如何通过菜单栏按钮重新打开已关闭/最小化的macOS应用窗口

macOS 点击状态栏按钮重新唤起已关闭/最小化主窗口实现

问题原因

原有代码无法生效的核心原因有5点:

  • 未强引用主窗口控制器(MainWindowController),窗口关闭后实例被系统自动回收,NSApp.windows中无法再获取到对应窗口实例
  • 直接通过NSApp.windows.last获取主窗口不可靠,出现其他窗口时会取错对象,窗口被回收后也取不到值
  • 未配置窗口关闭时不释放,NSWindow默认isReleasedWhenClosed属性为true,关闭后窗口实例会被直接销毁
  • 未实现应用终止策略,部分macOS版本下关闭最后一个窗口会直接退出应用,导致状态栏按钮一并消失
  • 未处理窗口最小化场景,最小化状态下仅调用makeKeyAndOrderFront无法自动恢复窗口显示

修改步骤

1. 配置Storyboard

打开Main.storyboard,选中主窗口对应的MainWindowController,在右侧Identity检查器面板中:

  • 将Storyboard ID设置为MainWindowController
  • 勾选Use Storyboard ID选项

2. 修改AppDelegate代码

在AppDelegate中新增对主窗口控制器的强引用,实现关窗不退出逻辑,修正状态栏按钮的唤起方法,完整代码如下:

class AppDelegate: NSObject, NSApplicationDelegate {

    private var statusItem: NSStatusItem!
    // 强引用主窗口控制器,防止实例被回收
    private var mainWindowController: MainWindowController?

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // 初始化状态栏按钮
        statusItem = NSStatusBar.system.statusItem(withLength: 16.0)
        if let button = statusItem.button {
            button.image = NSImage(named: "remote-control")
            button.image?.size = NSSize(width: 16.0, height: 16.0)
            button.image?.isTemplate = true
            button.action = #selector(bringToFront(sender:))
        }

        // 从Storyboard加载主窗口控制器
        let storyboard = NSStoryboard(name: "Main", bundle: nil)
        guard let mainWC = storyboard.instantiateController(withIdentifier: "MainWindowController") as? MainWindowController else { return }
        self.mainWindowController = mainWC
        mainWC.showWindow(nil)
    }

    // 关闭最后一个窗口时不终止应用
    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
        return false
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        print("terminate")
    }

    func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
        return true
    }

    @objc func bringToFront(sender: AnyObject?) {
        NSApplication.shared.activate(ignoringOtherApps: true)
        guard let mainWC = mainWindowController, let window = mainWC.window else { return }
        // 最小化状态下先恢复窗口
        if window.isMiniaturized {
            window.deminiaturize(nil)
        }
        // 将窗口前置并设为关键响应窗口
        window.makeKeyAndOrderFront(nil)
    }
}

3. 修改MainWindowController代码

在windowDidLoad中配置窗口关闭时不释放实例,完整代码如下:

class MainWindowController: NSWindowController {

    override func windowDidLoad() {
        super.windowDidLoad()

        window?.title = ""
        let styleMask: NSWindow.StyleMask = [.closable, .titled, .miniaturizable]
        window?.styleMask = styleMask
        // 关闭窗口时不释放实例,保证后续可以重新唤起
        window?.isReleasedWhenClosed = false
    }
}

验证效果

修改完成后运行应用:

  • 点击窗口关闭按钮,窗口消失,应用不退出,状态栏按钮保留
  • 点击窗口最小化按钮,窗口收进Dock
  • 两种场景下点击状态栏按钮,都可以正常将主窗口恢复并前置到屏幕最前方

内容的提问来源于stack exchange,提问作者Fake Panda

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 04:24:15