窗口对象

窗口是应用UI界面视图的容器,它负责接收用户的鼠标键盘等系统事件,转发消息到相关的接收者对象。AppKit提供的一些子类化的窗口还可以实现一些辅助交互功能,比如文件打开保存的对话框,字体颜色选择器等等。

每个应用启动后至少会打开一个窗口。当你运行多个应用App时,屏幕上会有多个窗口界面。我们把当前用户正在工作的应用的窗口称为活动或激活的窗口,其他应用的窗口相应的称为非活动的窗口。活动窗口顶部的title bar部分的颜色是高亮灰色选中状态。

activeWindo

可以接收输入事件(键盘,鼠标,触控板等外设)的窗口对象称为keyWindow;当前的活动窗口也称为mainWindow。一个时刻只能有一个keyWindow和一个mainWindow。

key-MainWindo

keyWindow和mainWindow可以是同一个窗口,也可以是不同的窗口。当mainWindow可以接收输入事件时,它同时也是keyWindow。

下面的图展示了一个编辑器App,它的窗口对象是活动窗口,也是mainWindow,同时可以接收输入是keyWindow。

keyMainWindo

一种特殊的window, 执行一些辅助功能。常用来做一些警告确认框,用户输入信息等对话框。

NSPanel类型的window不能做为mainWindow,只能做为keyWindow。

一些常用的子类有NSColorPanel(颜色选择),NSFontPanel(字体选择),NSSavePanel(保存打开文件),这些子类化的window将在面板和警告框章节做详细的介绍。

模态窗口

当有多个window在屏幕上时,用户可以点击切换到任何一个窗口上。有些特殊场景需要限制用户只能处理完当前的窗口的任务,只有关闭或处理完这个窗口才能继续操作其它的window。因此引入了模态窗口的概念。

有2种创建模态窗口的方法:

1.Modal windows

这种window比较霸道,当它启动后,此时只有这个window可以接收响应用户操作,无法切换到其他窗口操作,其他窗口也不能接收处理系统内部的各种事件。

使用NSApplication的runModalForWindow方法来创建Modal window

- (IBAction)showModelWindowAction:(id)sender {
    [[NSApplication sharedApplication]runModalForWindow:self.myWindow];
}

使用stopModal方法来结束模态。

[NSApplication sharedApplication]stopModal];

2.Modal sessions

比起Modal windows,Modal sessions方式创建的window稍微温和一些,允许响应快捷键和系统菜单,比如字体颜色选择这些panel面板.

启动Modal sessions 窗口

NSModalSession sessionCode = [[NSApplication sharedApplication]beginModalSessionForWindow:window];

结束Modal sessions 窗口

使用sessionCode做为参数来关闭Modal sessions 窗口

[[NSApplication sharedApplication]endModalSession:sessionCode];

注意任何一种模态窗口,都必须调用结束模态的方法去结束模态。如果点击了window左上角的关闭按钮,而没有执行结束模态的方法。整个系统仍然处于模态,其他窗口无法正常工作。

窗口界面组成

窗口对象包括titleBar,contentView内容视图,contentBoder底部边框区。

titleBar上面包括控制按钮,标题。

windowComponent

可以在Window的属性面板中配置UI界面。

windowProperties

Content Border 配置:默认是none 不显示出来,需要显示的话可以选择Small/Large Bottom Border其他选项

windowContentBorde

窗口编程控制

创建窗口对象

使用NSWindow类创建窗口对象,除了frame参数,还需要制定styleMask来确定窗口样式风格。

NSRect frame = CGRectMake(0, 0, 200, 200);
NSUInteger style =  NSTitledWindowMask | NSClosableWindowMask |NSMiniaturizableWindowMask | NSResizableWindowMask;
NSWindow *window = [NSWindow alloc]initWithContentRect:frame styleMask:style backing:NSBackingStoreBuffered defer:YES];
window.title = @"New Create Window";
[window makeKeyAndOrderFront:self];

1.styleMask: 按位表示的窗口风格参数

enum {
   NSBorderlessWindowMask = 0, //没有顶部titilebar边框
   NSTitledWindowMask = 1 << 0, //有顶部titilebar边框
   NSClosableWindowMask = 1 << 1,//带有关闭按钮
   NSMiniaturizableWindowMask = 1 << 2,//带有最小化按钮
   NSResizableWindowMask = 1 << 3,//恢复按钮
   NSTexturedBackgroundWindowMask = 1 << 8 //带纹理背景的window
};

2.backing:窗口绘制的缓存模式

enum {
   NSBackingStoreRetained       = 0,// 兼容老系统参数,基本很少用到
   NSBackingStoreNonretained  = 1,//不缓存直接绘制
   NSBackingStoreBuffered        = 2//缓存绘制
};

3.defer:表示延迟创建还是立即创建

窗口显示控制

1.窗口居屏幕中心显示

-(void)center;

2.前置显示窗口并且是其成为keyWindow

-(void)makeKeyAndOrderFront:(id)sender;

3.前置显示窗口

-(void)orderFront:(id)sender;

4.后置窗口,改变其在屏幕上的顺序

-(void)orderBack:(id)sender;

5.从屏幕上移除,隐藏窗口

-(void)orderOut:(id)sender;

窗口通知

当窗口状态变化时候,系统会发出相关通知消息。

NSWindowDidBecomeKeyNotification:窗口成为keyWindow
NSWindowDidBecomeMainNotification:窗口成为mainWindow
NSWindowDidMoveNotification:窗口移动
NSWindowDidResignKeyNotification:窗口不再是keyWindow
NSWindowDidResignMainNotification:窗口不再是mainWindow
NSWindowDidResizeNotification:窗口大小改变
NSWindowWillCloseNotification:关闭窗口

比如说有多个窗口来回切换操作,2个窗口之间会有业务影响,一个窗口的界面数据修改会影响另外一个窗口的界面数据。可以注册NSWindowDidBecomeMainNotification,NSWindowDidBecomeKeyNotification消息,当窗口每次接收到这个消息可以重新获取数据刷新界面。

注册关闭窗口的消息通知,可以在窗口关闭前完成一些资源释放,提醒用户有变化的数据是否需要保存等。

NSWindow中contentView

查看NSWindow.h头文件,有2个重要的属性说明一下

@property (strong) id /* NSView * */ contentView;
@property (strong) NSViewController *contentViewController NS_AVAILABLE_MAC(10_10);

通过xib设计window元素布局的话,直接从控件库拖上去就行了。在运行过程中要动态增加view元素到NSWindow的话,使用window的contentView,它代表了window的根视图。

有2种方法改变NSWindow的contentView

1.可以使用自定义的NSView或NSViewController的view,增加到contentView

[self.window.contentView addSubview:view]

2.OSX 10.10系统及以后,创建一个NSViewController子类,实例化后赋值给NSWindow的contentViewController。

NSViewController *myVC = [NSViewController alloc]init];
self.window.contentViewController = myVC;

设置Window的image和title

- (void)setWindowIcon {
    [self.window setRepresentedURL:[NSURL URLWithString:@"WindowTitle"]];
    [self.window setTitle:@"SQLiteApp"];
    NSImage *image = [NSImage imageNamed:@"windowIcon"];
    [[self.window standardWindowButton:NSWindowDocumentIconButton] setImage:image];
}

NSWindowTitleImage

设置窗口的背景颜色

[self.window setOpaque:NO];
[self.window setBackgroundColor:[NSColor greenColor]];

NSWindowColor

窗口创建和管理

一般情况下很少需要单独创建和管理窗口NSWindow对象。NSWindow的创建都是基于项目场景模版创建,或者通过NSWindowController创建管理的。

新建一个项目,工程中会自动生成的MainMenu.xib中会包含一个Window对象,这个Window是由AppDelegate管理的。

新建一个项目,勾选Create Document-Based Application,自动生成的Document.xib会包含一个Window对象,这个Window是由NSDocument文档类来管理的。

新建一个NSWindowController的子类WindowController,勾选使用xib,自动生成的WindowController.xib会包含一个Window对象。

后面#窗口控制器#章节部分会说明NSWindowController和AppDelegate如何管理的Window对象;#多文档应用#章节部分会说明NSDocument 如何管理的Window对象。