跟我一起学MAC编程吧(5) - 显示尺子
显示尺子, 菜单控制尺子的显示或者不显示,Cocoa 的NSScrollView 本身就支持标尺的显示,如果要显示标尺,很简单。
只需要在Controller的子类里面加入:
- (void)windowDidLoad
{
[super windowDidLoad];
// Set up the graphic view and its enclosing scroll view.
NSScrollView *enclosingScrollView = [_graphicView enclosingScrollView];
[enclosingScrollView setHasHorizontalRuler:YES];
[enclosingScrollView setHasVerticalRuler:YES];
[enclosingScrollView setRulersVisible:YES];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
尺子就可以显示了。但是有两个问题有点麻烦,第一,这个尺子的原点在左下角, 所以你看到纵向的尺子是反的(就我们习惯而言),第二个原因,如何控制尺子的显示或者不显示?这两个问题,大概花费了我三天的时间。请大家参照,Sketch例子吧,你能
够将有关标尺的代码剥离出来吗?你要是一起运行,但是它显示的很正确,通过菜单也能控制尺子的显示,如果你能新建
一个工程,单纯将尺子的控制代码剥离出来(基于文档的应用)你就会对程序的运行机制产生更神的认知,我建议大家试试吧。
NSMenuValidation
(informal protocol) 非正式协议
协议说明
这种非正式的协议允许更新您的应用程序的NSMenuItem启用或禁用状态。它宣称只有一个的方法,validateMenuItem:。默认情况下,每一个用户事件发生时,NSMenu自动启用和禁用----基于标准中描述的“自动更新NSMenuItems每个可见的菜单项”。实施validateMenuItem情况下,你要覆盖NSMenu的默认有效的办法。
启用或禁用NSMenuItems有两个方法:明确的方法--发送的setEnabled消息,或自动更新方法,如下所述。自动更新可以打开和关闭, 通过使用NSMenu的 setAutoenablesItems:消息。
自动更新NSMenuItems
当一个用户事件发生时,NSMenu对象更新它的每一个可见的菜单项的状态。要更新菜单项的状态,NSMenu试图找到响应到NSMenuItem的行动消息的对象。它会搜索给定的顺序中的下列对象,直到找到一个响应的的行动消息(注意,它实际上并没有发送动作消息):NSMenuItem的目标。如果目标是非空的,搜索在这里就结束了,无论目标是否响应。
关键窗口的响应链,从第一响应者开始。
关键窗口本身。
关键窗口的Delegate。
主窗口的响应链,第一个响应者开始。
主窗口本身。
主窗口的Delegate。
NSApplication对象。
NSApplication对象的Delegate。
上面的协议的内容是我找到并翻译的。菜单有两种工作方式,一种直接拉线到它的属主方法, 这很简单,另外一种自动模式,理解起来就有点困难。你可以把菜单执行的方法放到窗口的子类里面,这样拉线的方式不可能了,因为界面直接看不到这个方法。这时候,需要使用first Reponder 这个对象。
下面是我找到的一位朋友对于这个问题的解释:
File's Owner 表示视图控制器。用来关联 IB 中的 outlet (textfield, label)与实例变量(library classes 中定义)的关联。 First Responder 表示当前响应用户触摸的屏幕上的对象。在应用程序生命周期内, First Responder 在用户与屏幕交互时变化。例如,假设有一个表单。当用户触摸表单中的某个文本域时,那个文本域将成为活动文本域,并担当 First Responder 的角色。
你需要为菜单设置selector ,对应于 first Responder, 如果你建立了那个于菜单方法,你会发现在First Responder里面你可以找到它。并将这个方法于菜单连接。
程序执行时候,根据菜单的非正式协议,找到这个方法。用于显示菜单,或者执行方法。这时候,两个不起眼的方法会非常重要:
// An override of the NSResponder method.
- (BOOL)acceptsFirstResponder {
// This view can of course handle lots of action messages.
return YES;
}
// An override of the NSView method.
- (BOOL)isFlipped {
// Put (0, 0) at the top-left of the view.
return YES;
}
第一个函数, 是表示这个窗口能否作为 First Responder, 如果没有这个函数的话(我一直没留意这个方法,导致程序无法执行到我的标尺显示方法),那么这个窗口就不能作为 First Responder,菜单非正式协议的就找不到它。而第二个方法,它将视图的远点从左下角移动到了左上角, 于是尺子的显示方向就正确了。