参考:
《cocoa 入门》第二版16章附属窗口
环境:
Xcode10
目标:
创建简单查看器告诉用户文本视图有多少字符
进阶:
单词数,段落数,查看器动态更新
描述:
当创建辅助xib文件(窗口)时,需要将file‘s owner代理赋给某个类,给类将加载xib文件并负责协调附属窗口与应用程序其他部分的关系。
过程:
1.创建cocoa application工程项目,在自动生成的ViewController.h视图控制器里声明插座变量和动作方法——
{
IBOutlet NSPanel* InfoPanel;//对查看器面板的引用
IBOutlet NSWindowController* infoPanelController;//作为面板的窗口控制器
IBOutlet NSTextField* textLengthField;//查看器面板的字符数信息框
IBOutlet NSTextField* textSegmentField;//段落数
IBOutlet NSTextField* textWordField;//单词数
IBOutlet NSTextView* textView;//应用程序的文本视图
}
-(IBAction)showInfoPanel:(id)sender;//点击菜单项触发的动作
2.创建查看器面板——新建文件
任意命名为InfoPanel.xib,⚠️名字将在代码中用到。
3.绑定
main.storyboard上——从菜单menu里建一个菜单项,连接到控制器的showInfoPanel:动作中。从控件库拉一个带滚动条的文本视图textview到viewcontroll中,从控制器(蓝色小正方形)连接textview插座变量到文本视图textview,调整为自动适应大小。
InfoPanel.xib上——先从file‘s owner中选择代理对象,这里选viewcontroller,此时file’s owner为viewcontroller的替身。然后以同样步骤搭控件,从file‘s owner连接到控件选择对应的插座变量。
4.实现showInfoPanel:方法
-(IBAction)showInfoPanel:(id)sender
{
if(!infoPanelController){
//[NSBundle loadNibNamed:@"InfoPanel" owner:self];//该版本在osx10.0-10.8
[[NSBundle mainBundle] loadNibNamed:@"InfoPanel" owner:self topLevelObjects:nil];
infoPanelController = [[NSWindowController alloc] initWithWindow:InfoPanel];//缺少这句初始化,打开菜单关闭后再次编辑文本会出错
}
[textLengthField setIntValue:(int)[[textView textStorage] length]];
[textWordField setIntValue:(int)[[[textView textStorage] words] count]];
[textSegmentField setIntValue:(int)[[[textView textStorage] paragraphs] count]];
[infoPanelController showWindow:self];
}
5.添加通告来实现查看器动态显示
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSNotificationCenter * center =[NSNotificationCenter defaultCenter];//将viewcontroller实例添加为默认通告中心的监听者,监听textView对象上的NSTextDidChangeNotification事件
[center addObserver:self selector:@selector(textDidChange:) name:NSTextDidChangeNotification object:textView];
}
实现回调方法,该方法在文本改变时由通告中心调用
-(void)textDidChange:(NSNotification *)notification
{
[textLengthField setIntValue:(int)[[textView textStorage] length]];
[textWordField setIntValue:(int)[[[textView textStorage] words] count]];
[textSegmentField setIntValue:(int)[[[textView textStorage] paragraphs] count]];
}