01. NSWindow 窗口对象

窗口概述

窗口的类型

窗口是View视图的容器,而VIew视图是UI控件的容器。窗口也负责接收用户的鼠标键盘等系统事件,然后负责转发消息到相应的接收对象。在Appkit中有很多window的子类,可以提供更多功能,提供更好友好的交互。Mac OS的窗口中一共有以下几种不同的状态/分类:

  • deactive window:多个app同时打开时,只有一个可以是active状态,其它全是deactive状态;
  • active window:多个app同时打开时,当前可操作的app;
  • key window:当前active window可操作的窗口,一般用于接收系统事件;
  • main window:当前active window可操作的窗口,main window也可以是key window;
    在这里插入图片描述

有一个控件需要注意,NSPanel 为面板对象,它只能是main window而不能是key window。

窗口的组成

在这里插入图片描述
在XIB文件导航中选择windows对象即可对window进行个性化的配置,就是上节课所说的右侧的8个inspector面板,比如在 size inspector 面板中 content border 选择可以设置其bottom是否显示,默认为none不显示;

模态窗口

其实就是传统所说的Dialog,这种窗口弹出后除非手动关闭,否则只能在这个窗口中操作。在Mac OS中分为两种:

  • modal window:弹出显示,独占;
  • session window:弹出显示,不独占;
    在这里插入图片描述

设计实现

  1. 在xib中添加一个NSWindow对象,连接到AppDelegate.swift文件中
  2. 添加一个动作按钮,绑定IBAction事件;
  3. 添加Observer,在关闭时结束窗口模态事件(因为此时是设置了整体的状态,不取消状态会导致整个App不能再操作);

代码实现如下:

import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {

    @IBOutlet var window: NSWindow!

    @IBOutlet weak var modalWindow: NSWindow!
    
    var sessionCode : NSApplication.ModalSession?
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        // 这个侦听器对modal 和 sessions 同时生效必须要写
        NotificationCenter.default.addObserver(self, selector: #selector(self.modalWindowClose(_:)), name: NSWindow.willCloseNotification, object: nil)
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        NotificationCenter.default.removeObserver(self)
    }
    
    //显示modal窗口
    @IBAction func showModelWindow(_ sender: NSButton) {
        NSApplication.shared.runModal(for: self.modalWindow)
        self.modalWindow.center()
    }
    
    //显示session窗口
    @IBAction func showSessionWindow(_ sender: NSButton) {
        sessionCode = NSApplication.shared.beginModalSession(for: self.modalWindow)
    }
    
    @objc func modalWindowClose(_ notitification: Notification){
        //关闭session窗口状态
        if let sessionCode = sessionCode {
            NSApplication.shared.endModalSession(sessionCode)
            self.sessionCode = nil
        }
        
        //关闭modal窗口状态
        if let window = notitification.object as? NSWindow {
            if self.modalWindow == window {
                NSApplication.shared.stopModal()
            }
            //作用同 applicationShouldTerminateAfterLastWindowClosed
            if window == self.window! {
                NSApp.terminate(self)
            }
        }
    }
}

在关闭最后一个window时整个应用退出,等价于上面代码中侦听器的关闭方式:

    // 在关闭最后一个window时应用退出
    func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
        return true
    }

在应用关闭后,点击Dock菜单再次打开应用,这个方法和上面的方法是一个互斥的关系,所以此方法返回true时applicationShouldTerminateAfterLastWindowClosed()一定要返回false:

    func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
        self.window.makeKeyAndOrderFront(self)
        return true
    }

编程实现

通过程序来创建window窗口:

import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {
    
    var windowItem: NSWindow!
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        
    }

    func applicationWillTerminate(_ aNotification: Notification) {
        NotificationCenter.default.removeObserver(self)
    }
    
    @IBAction func createWindow(_ sender: NSButton) {
        let frame = CGRect(x:0, y:0, width: 400, height: 300)
        //设置按钮样式
        let style : NSWindow.StyleMask = [NSWindow.StyleMask.titled,NSWindow.StyleMask.closable,NSWindow.StyleMask.resizable]
        
        /*
         backing:缓存样式,完整写法是 NSWindow.BackingStoreType.buffered
         defer:表示立即创建还是延迟创建
         */
        windowItem = NSWindow(contentRect: frame, styleMask: style, backing: .buffered, defer: true)
        windowItem.title = "window by code"
        //显示窗口
        windowItem.makeKeyAndOrderFront(self)
        //点击窗口背景,支持鼠标拖动窗口
        windowItem.isMovableByWindowBackground = true
        //居中显示
        windowItem.center();
        //全屏
        windowItem.toggleFullScreen(myWindow)
    }
}

上面代码有一个问题,就是窗口只能显示一次,关闭后就不能再显示了,后面在NSWindowController控制器一节中会详细讲解:https://korgs.blog.csdn.net/article/details/142720096

窗口设置

窗口样式设置

可设置标题,图标和背景等

    func setWindowTitleImage(){
        self.window.representedURL = URL(string:"WindowTitle")
        self.window.title = "WindowItem"
        let image = NSImage(named: "WindowIcon")
        //这行代码可以把图标放在源码下面,而不用放在Assets.xcassets中
        //let image = NSImage(named: NSImage.Name(rawValue: "AppIcon.png"))
        
        self.window.standardWindowButton(.documentIconButton)?.image = image
        
        self.window.backgroundColor = NSColor.gray
    }

窗口工具栏设置

以下代码会在标题栏上增加一个名为button的按钮

    func addButtonToTitleBar(){
        let titleView = self.window.standardWindowButton(.closeButton)?.superview
        let button = NSButton()
        let x = (self.window.contentView?.frame.size.width)! - 100
        let frame = CGRect(x: x, y: 0, width: 80, height: 24)
        button.frame = frame
        button.title = "button"
        button.bezelStyle = .rounded
        titleView?.addSubview(button)
    }

在这里插入图片描述

通过storyboard 管理UI

通常情况下很少有场景需要手工创建NSWindow对象,如果需要的话一般会通过NSWindowController对象来创建和管理。默认情况下NSWindow对象会交由AppDelegate对象代理管理(AppDelegate就是一个普通类,如有需要也可以换成其它类),不建议手功创建NSWindow的原因大体如下:

  1. 采用xib设计时,xib中会包含一个window对象,它AppDelegate代理;
  2. 采用storyboard设计时,会自动生成一个controller类,由它来管理Window对象;
  3. NSWindow的设置非常复杂;
    中会包含一个window对象
    通过上面设置创建Storyboard类型的项目后,项目的源码大体如下:
    在这里插入图片描述
    和XIB类型的项目区别是,Storyboard会自动创建一个ViewController.swift文件,原来在AppDelegate.swift中的NSWindow(通过NSView引用访问)对象会转移绑定在此Controller中。这样就比较方便管理,职责也比较清楚,即AppDelegate管理App, 而ViewController管理Window。
import Cocoa

class ViewController: NSViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    //注意这里设置的方法名变了
    override func viewDidAppear() {
        self.view.window?.isRestorable = false
        self.view.window?.title = "windowCustom"
        self.view.window?.center()
    }

    override var representedObject: Any? {
        didSet {
            super.viewDidLoad()
        }
    }
}

这一小节涉及到NSWindow, NSView两个控件,先做到会用,后面会详细讲这两个控件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

korgs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值