【问题标题】:Swift open new window programmatically in macOSSwift 在 macOS 中以编程方式打开新窗口
【发布时间】:2021-01-05 14:12:51
【问题描述】:

在使用 macOS 的 Swift 中: 通过在 AppDelegate 中删除 @NSApplicationMain(并创建 NSWindowController 的子类),我以编程方式创建主窗口,而不使用情节提要等:

//@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

    var window: NSWindow!
    var viewController: NSViewController!
    var windowController: NSWindowController!


    func configMainWindow(_ viewController: NSViewController) {
        window = NSWindow(contentRect: NSRect(x: 0, y: 0, width: 800, height: 600),
                      styleMask: [NSWindow.StyleMask.closable, NSWindow.StyleMask.titled, NSWindow.StyleMask.resizable, NSWindow.StyleMask.miniaturizable],
                      backing: NSWindow.BackingStoreType.buffered,
                      defer: false)
        window.title = "My App"
        window.setFrameAutosaveName("My App")
        window.center()
        window.isOpaque = false
        window.isMovableByWindowBackground = true
        window.backgroundColor = NSColor.white
        window.makeKeyAndOrderFront(nil)
        window.contentViewController = viewController
        windowController = WindowController(window: window)
    }


    func applicationDidFinishLaunching(_ aNotification: Notification) {
        viewController = ViewController()
        configMainWindow(viewController)
    }
}

windowController 附加了一个 toolbarstatusBarmenuBar: (仅从 NIB 加载 menuBar。MainMenuAction 类处理菜单选择。)

class WindowController: NSWindowController, NSWindowDelegate {

    var toolbarController = ToolbarController()
    var statusBarController = StatusBarController()
    var mainMenuAction: MainMenuAction?


    override init(window: NSWindow?) {
        super.init(window: window)
        window?.toolbar = toolbarController.toolbar
        window?.delegate = self

        var topLevelObjects: NSArray? = []
        Bundle.main.loadNibNamed("MainMenu", owner: self, topLevelObjects: &topLevelObjects)
        NSApplication.shared.mainMenu = topLevelObjects?.filter { $0 is NSMenu }.first as? NSMenu
        self.mainMenuAction = MainMenuAction.shared
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    override func windowDidLoad() {
        if let window = window {
            if let view = window.contentView {
                view.wantsLayer = true
                window.titleVisibility = .hidden
                window.titlebarAppearsTransparent = true
                window.backgroundColor = .white
            }
        }
    }
}

另外,我需要添加一个 ma​​in.swift 文件: (感谢提醒我,apodidae)

let delegate = AppDelegate()
NSApplication.shared.delegate = delegate
_ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)

我试过了:

    let vc = NSViewController()
    let win = configWindow(vc, windowWidth: 420, windowHeight: 673)
    let wc = NSWindowController(window: win)
    wc.window?.present
    vc.view.window?.contentViewController = vc

我从 AppDelegate 复制了方法 configMainWindow,以创建允许我指定大小和 vc 的 configWindow。


但是如何使用自定义 sizestyle 打开一个新窗口(通过新类中的某个方法 - 以编程方式)?

请提供代码示例。

【问题讨论】:

  • 请贴出你试过的代码,和configMainWindow差不多。注意:菜单栏属于应用程序,而不是窗口。最好让NSApplicationAppDelegate 创建菜单栏。

标签: swift macos cocoa window programmatically-created


【解决方案1】:

以下演示创建了由自定义类中的方法调用的第二个窗口。它可以通过添加“swift.main”文件并用以下代码替换 AppDelegate 在 Xcode 中运行:

import Cocoa

class Abc : NSObject {
var panel: NSPanel!

func buildWnd2() {
 let _panelW : CGFloat = 200
 let _panelH : CGFloat = 200

 panel = NSPanel(contentRect:NSMakeRect(9300, 1300, _panelW, _panelH), styleMask:[.titled, .closable, .utilityWindow],
  backing:.buffered, defer: false)         
 panel.isFloatingPanel = true
 panel.title = "NSPanel"
 panel.orderFront(nil)
}
}

let abc = Abc()

class AppDelegate: NSObject, NSApplicationDelegate {
var window:NSWindow!

@objc func myBtnAction(_ sender:AnyObject ) {
 abc.buildWnd2()
}

func buildMenu() {
 let mainMenu = NSMenu()
 NSApp.mainMenu = mainMenu
 // **** App menu **** //
 let appMenuItem = NSMenuItem()
 mainMenu.addItem(appMenuItem)
 let appMenu = NSMenu()
 appMenuItem.submenu = appMenu
 appMenu.addItem(withTitle: "Quit", action:#selector(NSApplication.terminate), keyEquivalent: "q") 
}
    
func buildWnd() {
    
let _wndW : CGFloat = 400
let _wndH : CGFloat = 300

 window = NSWindow(contentRect:NSMakeRect(0,0,_wndW,_wndH),styleMask:[.titled, .closable, .miniaturizable, .resizable], backing:.buffered, defer:false)
 window.center()
 window.title = "Swift Test Window"
 window.makeKeyAndOrderFront(window)

// **** Button **** //
let myBtn = NSButton (frame:NSMakeRect( 100, 100, 175, 30 ))
 myBtn.bezelStyle = .rounded
 myBtn.autoresizingMask = [.maxXMargin,.minYMargin]
 myBtn.title = "Build Second Window"
 myBtn.action = #selector(self.myBtnAction(_:))
 window.contentView!.addSubview (myBtn)

// **** Quit btn **** //
let quitBtn = NSButton (frame:NSMakeRect( _wndW - 50, 10, 40, 40 ))
 quitBtn.bezelStyle = .circular
 quitBtn.autoresizingMask = [.minXMargin,.maxYMargin]
 quitBtn.title = "Q"
 quitBtn.action = #selector(NSApplication.terminate)
 window.contentView!.addSubview(quitBtn)
}
 
func applicationDidFinishLaunching(_ notification: Notification) {
 buildMenu()
 buildWnd()
}

func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
 return true
}

}
let appDelegate = AppDelegate()

// **** main.swift **** //
let app = NSApplication.shared
app.delegate = appDelegate
app.setActivationPolicy(.regular)
app.activate(ignoringOtherApps:true)
app.run()

【讨论】:

  • 在 Willeke 的提示下,我发现我可以创建一个 NSWindow 而无需附加 VC 或 WC 来显示窗口。也许我正在制作窗口但没有orderFront(nil) 属性,它不会显示。 (感谢 apodidae。)但是现在另一个问题.. 如果我尝试关闭新窗口,它会崩溃并将我带到 main.swift(使用我的代码或 apodidae 的)。 (这可能是由于 mainMenu - 你能提供一个建议 Willeke。)
  • 我提供的演示在关闭第二个窗口时不会崩溃。
  • 是的,谢谢,我仍在使用 NSWindow 而不是 NSPanel。现在好了。
猜你喜欢
  • 2020-12-10
  • 2021-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-04
相关资源
最近更新 更多