本文是Apple Documentation Archive Window Programming Guide的学习笔记。

设置窗口图像的属性

Setting Attributes for the Window’s Image

窗口服务器(Window Server)把每一个窗口跟一个显示窗口的设备(简称窗显设备)关联。窗显设备拥有一个窗口的图像(二维像素数组)。窗口服务器会给窗显设备分配一个在应用内唯一的标识,叫做窗口号,可以通过windowNumber获取。并且,每个窗口有一个作图相关的状态,被窗口中所有的视图共享,可以通过gState获取。(每个视图也可以拥有自己的作图状态)。

窗显设备的属性backing store type决定了窗口图像是如何存储的。这个属性可以使用setBackingType: 设置为三种类型。第一种,缓冲式的窗显设备会先把窗口的图像保存到缓冲中,然后在屏幕上输出。第二种,留存式的窗显设备会直接在屏幕上作图,但是依然持有缓冲,可以保存当前窗口被遮蔽的部分。第三种,非留存式的窗显设备会直接在屏幕上输出,但是没有持有缓冲,窗口的遮蔽部分需要重新绘制才能显示。对于第三种而言,重绘的过程可能不会是即时的,用户有可能看到一个失效的窗口。第二种类型和第三种类型的窗口会比第一种更快出现在屏幕上,但因此也可能出现“快闪”的效果。

窗口服务器可以选择把一个窗口的图像放在内存,或者显存之中。preferredBackingLocation可以查询窗口服务器对此的偏好。应用程序可以通过setPreferredBackingLocation:来修改此偏好,不过窗口服务器不一定能够按照设置的偏好操作。

窗口初始化的时候的一个参数defer可以用来控制什么时候初始化窗显设备。既可以在窗口初始化的时候初始化,也可以在窗口需要在屏幕上显示的时候初始化。

当窗口不在屏幕上显示的时候,窗显设备是不需要的,释放它可以回收内存。setOneShot: 可以用来设置是否在窗口从屏幕上移除的时候释放窗显设备。

缓存的窗口图像是带有颜色深度的,默认情况下至少16bit,一般和显示器的一致。颜色深度可以通过setDepthLimit:设置。通过setDynamicDepthLimit:可以让窗口自动匹配显示器屏幕的颜色深度,这个操作会覆盖之前手动设置的颜色深度。

窗口的图像是保存的内存(或者显存)里面的,这意味当前应用的窗口图像是可以被其他进程读取的。但是默认情况下系统禁止跨进程改写窗口图像。setSharingType:可以用来改写这个设置。设为NSWindowSharingNone会禁止其他进程读取当前应用窗口的图像,但是这样做的话会影响很多系统既有的功能。设为NSWindowSharingReadWrite可以允许其他进程读取当前应用窗口的图像。

处理窗口事件

Handling Events in Windows

根据NSResponder Class Reference的说明,事件是通过sendEvent:到达窗口的。一个键盘事件被被键窗口接收,一个鼠标事件被指针所在的窗口接收。如果一个事件改变了窗口的大小,那么在事件发生之后,窗口的代理会收到这个事件的通知。窗口把事件转发给它的响应链,最终会到达窗口的某个视图。

其他参考:

Cocoa Event Handling Guide

在窗口中使用键盘接口控件

Using Keyboard Interface Control in Windows

窗口事件的第一响应者(first responder)通常是窗口上被用户点击而激活的视图控件。对于从NSControl派生出来的输入类型的视图控件,用户可以通过Tab键和Shift键来选择第一响应者。 NSView带有相应的方法来帮助设置此机制。作为第一响应者的视图称为键视图。窗口中能够成为键视图的视图会被链接在一起,形成一个环路(key view loop),然后可以设置这个环路的某个视图作为第一响应者。在interfaceBuilder上通过nextKeyView outlet和initialFirstResponder outlet可以帮助做上述的设置。

除了第一响应者之外,窗口还可以通过setDefaultButtonCell: 设置一个默认按键,来相应用户对于回车键的敲击。如果是通过interfaceBuilder操作,可以将按键对于的键设为'\r'

使用窗口的字段编辑器

Using the Window’s Field Editor

每个窗口都有一个默认的共享的文本对象(一个输入字段,默认是NSTextView类型),用来做简易的编辑功能。当需要的时候,这个对象被插入窗口的视图树中,使用完成以后,就会从视图树中移除。NSTextField以及其他输入控件都使用这个文本对象。fieldEditor:forObject:返回窗口的文本对象。窗口代理的windowWillReturnFieldEditor:toObject:可以用来修改返回的对象。

NSWindow的派生类可以自定义fieldEditor:forObject:来返回一个NSTextView以外的文本对象。

使用窗口的通知和代理的方法

Using Window Notifications and Delegate Methods

窗口提供了不同事件的通知同能(比如最大化窗口、最小化、获得输入等等)。这些通知可以映射到代理的方法。一个窗口的代理会自动注册并接收这些通知。

除了通知之外,NSWindow还给它的监护(delegate)提供以下方法:

  • windowShouldClose:
  • windowWillResize:toSize:,
  • windowWillUseStandardFrame:defaultFrame:,
  • windowWillReturnFieldEditor:toObject:,

拖入拖出图片到窗口

Dragging Images to and from Windows

NSWindow定义了一个拖动图片的方法dragImage:at:offset:event:pasteboard:source:slideBack:可以让你拖动窗口视图上的图片。如果往窗口拖入图片,那么窗口必须注册自己可以处理的图片类型registerForDraggedTypes:,取消注册可以使用unregisterDraggedTypes

改变鼠标指针图像

Updating the Cursor Image in a Window

鼠标指针的图像是可以在窗口的视图级别自定定义的。这需要用到NSTrackingArea类,以及NSRespondercursorUpdate:方法。

Using Tracking-Area Objects

缓存窗口图像

Caching Window Images

有时候需要缓存窗口图像(整体或者部分),并在需要的时候恢复。NSWindow的下面几个方法可以提供帮助

  • cacheImageInRect:
  • restoreCachedImage
  • discardCachedImage

附带文档

Document-based App Programming Cocoa Event Handling Guide

关于术语使用的反思

或许应该把Window翻译成窗格,Window Server翻译成窗格服务端。Delegate翻译成监护。

(系列完)