如何将nsview 背景图片中的东西清空,就是在custom view 中绘制的图画,清除后重新画

第十七章:&自定义View
------------------------------
第十七章: 自定义View
程序中所有的可视对象要么是window,要么是view.在这一章中,你将创建一个NSView的子类.
随着时间的推移,你一般会需要创建自定义的view来完成自定义画图和事件响应.即使你没有打算这样做,你也应该通过学习创建view类来了解cocoa的内部工作机制
window是NSWindow的对象.每个window都会有多个views,每个view描述window中的一个矩形区域.
view负责该区域的画图动作以及鼠标事件响应. view也可以响应键盘消息. 你以及和多个view的子类打过交道了:
NSButton, NSTextField,NSTableView,和NSColorWell 都是view
(注意,window不是NSView的子类)
View的层次
view是按一定层次关系组织(如图17.1) .window包含了一个叫做content
view的view.该view填满了整个window内部区域[除去title bar.
你可以在NSWindow类中找到contentView 和 setContentView方法] 通常,content
view会有自己的子view.而这些子view有会有自己的子view.一个view知道自己的父view和子view,并知道自己所属的窗口
[到NSView类声明中,找找和它们相关的方法]
&&& - (NSView
&&& - (NSArray
&&& - (NSWindow
任何类型的view [这么说是指
view的子类,如NSButton,NSTableView...]都可以包含多个子view.不过对于大部分类型的view,我们不会给它添加子view.
下面5中类型view通常有子view
1. window的content view
2. NSBox. box中的内容就是它的子view
3. NSScrollView. scroll view中包含的view就是它的子view. scroll
bar也是它的子view
4. NSSplitView. SplitView中的view就是它的子view 如图 17.2
5. NSTabView.& 当用户点选不同的tab时.
不同的子view交替切换如图17.3
-- 让一个View画自己 --
在本节中,将创建一个简单的view. 它将自己刷成绿色.就像17.4 [灰色的..呵呵]
新建一个Cocoa Application工程, 命名为ImageFun. 点选File-&New
file菜单,创建一个Objective-C NSView子类.命名为StretchView.
--创建一个View 子类的对象--
打开MainMenu.nib.
从Library中拖一个CustomView(view&cell-&Layout
View)放置在window上.如图17.5
将view大小改变接近window. 然后打开info panel. 将它的类设置成为StretchView.如图17.6
--大小检查--
StretcView对象是window content view的子view. 这就有个有意思的问题:当父view改变大小的时候,
view有什么反应呢?在info panel中有一个tab页面来指定这样的行为. 打开Size Info Panel.
设置如图17.7. 现在你改变窗口大小. view的大小会跟着变化了.
-- drawRect--
当一个view需要刷新显示时,它将会收到drawRect:的消息,参数为一个需要重画的矩形区域,
这个方法会被自动调用-你不需要直接在代码中调用.
如果你需要让一个view重画,可以调用方法setNeedsDisplays
[myView setNeedsDisplay:YES];
该方法将myView设置成"脏"的. 在事件处理中,myView将被重画
[cocoa , 系统]在调用drawView:前, 会对这个view lock focus.
每一个view都有自己的graphics context-包含了view的坐标系统,当前颜色,当前字体等. 当view被lock
focus,它的graphics context将激活,而当unlock focus后,它的graphics
context将不是激活状态. 任何时候的draw命令都是在当前激活的graphics context进行
[对于Mac的画图draw, 可以看看Quarz 2D . graphics context也是它里面的概念咯. 其实cocoa
view 画图也是通过Quarz 2D来实现, 要对屏幕显卡进行绘制,那么就要有一个绘制环境,这个环境也就是graphics
context , cocoa 中在每个view中保存了一个各自的graphics context .
绘制到那个view时就将它的graphics context设置为当前Quarz用来绘制的graphics context -
通过lock focus]
你可以使用NSBezierPath来绘制线条,圆形,曲线和矩形. 你可以使用NSImage来在view上绘制合成图像.
在本节例子中, 绘制一个绿色的矩形
打开StretchView.m. 添加如下代码
- (void)drawRect:(NSRect)rect
&&& NSRect
bounds = [self bounds];
&&& [[NSColor
greenColor] set];
[NSBezierPath fillRect:bounds];
如图17.10, NSRect结构由两个成员组成:origin - NSPoint类型, 和size -
NSSize类型
NSSize结构有两个成员: width和height(都是float类型)
NSPoint结构有两个成员:x和y(都是float类型)
因为性能的原因,Objective-C类中很少使用到结构. 你有可能用到的一些cocoa结构:
NSPoint,NSRect,NSRange,NSDecimal 和NSAffineTransformStruct等等.
NSRange描述区间. NSDecimal描述数字精度, NSAffineTransformStruct描述图形线性变换
注意,view通过bounds知道自己的位置.
在drawRect中得到bounds区域,将当前color设置为绿色,再使用当前色来填充整个bounds区域
通过参数传递的NSRect描述了这个view需要重画的"脏"的区域.它有可能会小于整个view的大小.如果绘制比较费时间的东西,可以只对该脏的区域进行重新绘制
setNeedsDisplay:将激发view整个可见区域重画.
如果需要激发view某个指定区域进行重话可以使用setNeedsDisplayInRect:
NSRect dirtyR
dirtyRect = NSMakeRect(0, 0, 50, 50);
[myView setNeedsDisplayInRect:dirtyRect];
编译运行程序.试着改变window的大小看看
-- 使用NSBezierPath绘制--
如果想绘制线条,曲线或多边形,可以使用NSBezierPath. 前面,你使用了NSBezierPath的fillRect
类方法来给view上色.在这节中你将使用NSBezierPath绘制随机点间的线条
首先你需要一个成员变量来保存NSBezierPath对象.并创建一个方法来返回随机点.
在StretchView.h中修改如下
#import &Cocoa/Cocoa.h&
@interface StretchView : NSView
&&& NSBezierPath
- (NSPoint)randomP
在StretchView.m中,重载initWithFrame方法-这是NSView的designated
initializer[还记得它吧] . 它会在view对象创建时自动调用[在这个例子中,是在nib文件加载是cocoa调用].
修改StretchView.m 在initWithFrame中,创建了一个path对象
#import "StretchView.h"
@implementation StretchView
- (id)initWithFrame:(NSRect)rect
&&& if (![super
initWithFrame:rect])
&&& // Seed
the random number generator
srandom(time(NULL));
&&& // Create
a path object
&&& path =
[[NSBezierPath alloc] init];
setLineWidth:3.0];
&&& NSPoint p =
[self randomPoint];
moveToPoint:p];
&&& for (i = 0;
i & 15; i++) {
p = [self randomPoint];
[path lineToPoint:p];
closePath];
&&& return
- (void)dealloc
&&& [super
// randomPoint returns a random point inside the view
- (NSPoint)randomPoint
&&& NSPoint
&&& NSRect r =
[self bounds];
&&& result.x =
r.origin.x + random() % (int)r.size.
&&& result.y =
r.origin.y + random() % (int)r.size.
&&& return
- (void)drawRect:(NSRect)rect
&&& NSRect
bounds = [self bounds];
&&& // Fill
the view with green
&&& [[NSColor
greenColor] set];
[NSBezierPath fillRect: bounds];
&&& // Draw
the path in white
&&& [[NSColor
whiteColor] set];
编译运行程序,怎么样?酷吧! 好了,现在用[path fill] 代替[path stroke]看看,有什么不一样?
-- NSScrollView--
在美术世界里,在同样的质量下,绘制的越大就越美观啊. 你的view很漂亮了.不过能不能让它更大一点呢., 你需要将它放置在scroll
view中如图17.12
scroll view由3个部分组成: document view, content view,和scroll bar.
在本例中.你的view将成为document view,并显示在content view中-它是NSClipView的对象
虽然这个看上去复杂,其实很容易办到. 实际上都不需要添加代码.
打开mainmenu.nib文件,选中view.& 从LayOut 菜单中选择Embed
Objects in Scroll View如图17.13
当window改变大小时,你希望scroll view跟着改变,而document view确不改变. 打开Size
Inspector, 选择Scroll view. 设置他的Size
Inspector,这样它就跟着window改变了如图17.14
注意view的长和宽
双击scroll view内部,选中document view.你可以看到这是inspecotr的标题变成 Stretch View
Size. 将view的大小修改为scroll view的2倍. 同时绑定左下角并不要跟随改变大小如图17.15.
编译运行程序
-- 通过程序创建View--
你可以在Interface Builder中实例化多个view.
有时候,你会需要通过程序来创建view.例如,假定你希望在window上创建一个button
NSView *superview = [window contentView];
NSRect frame = NSMakeRect(10, 10, 200, 100);
NSButton *button = [[NSButton alloc] initWithFrame:frame];
[button setTitle:@"Click me!"];
[superview addSubview:button];
[button release];
--思考:cells--
NSControl从NSView继承得到. 因为view有自己的graphics context. 这让view成为一个大,高价的类.
当初,在提供NSButton类时, 有人要编写一个计算器程序, 他第一件事就是创建10行10列的NSButton.
这样就有100个view别创建,效率是相当低啊. 后来,有人想到了一个聪明的主意: 将NSButton的大脑移到另外一个类[大脑?
就是button的主要功能了](不再是view类).并创建一个大的view(叫做NSMatrix).
用来装那100个button大脑. 我们把这个button 大脑内叫 NSButtonCell
[这个就如设计原则所说,内的聚合咯,少用继承,多用聚合,看到好处了] 如图17.16
到最后,NSButton就是一个简单的view再加上它的大脑 NSButtonCell. button
cell做了所有事情,而NSButton只是window上的一块绘制区域如图17.17
同样的.NSSlider就是一个包含了NSSliderCell的view.& NSTextField
就是一个包含了NSTextFieldCell 的view.& NSColorWell,
抱歉,它没有cell :)
你拖一个control到window上,然后选择Embed Objects In -&
Martix. 这样就创建了一个NSMatrix. 可以按住Option拖动martix 来设定它的行列数.如图17.18
NSMatrix 有一个Target和action. Cell也有target和action.
如果cell点击,cell的target ,action将激发,如果cell没有设置它的target
和action.那么matirx的target,acton将激发.
在处理matirx时,你常常要面对这样的问天,哪个cell激活?cell也可以设置它的tag
- (IBAction)myAction:(id)sender {
&&& id theCell =
[sender selectedCell];
&&& int theTag =
[theCell tag];
cell的tag可以通过Interface Builder来设定
-- 思考: isFlipped --
PDF和PostScript使用的是标准的迪卡尔坐标系统.当向上移动页面时,y值增加. Quartz使用了同样的模型.
view的原点在左下点.
对于有些绘制,如果让原点在左上方会更方便. 也就是当向下移动页面是y增加,这时我们叫这个view是filpped的
你通过重载方法ifFlipped来filp一个view
- (BOOL)isFlipped
&&& return
当我们讨论坐标系统时, x和y是使用点来计数的. 一般72点=1英寸.
默认的1.0point及时屏幕上的一个像素.不过,你可以通过改变坐标系统来改变point的大小
// Make everything in the view twice as large
NSSize newS
newScale.width = 2.0;
newScale.height = 2.0;
[myView scaleUnitSquareToSize:newScale];
[myView setNeedsDisplay:YES];
-- 挑战 --
NSBezierPath可以会在Bezier曲线. 绘制看看咯.(请查看NSBezierPath帮助文档)
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。第十七章: 自定义View - pengyingh - 博客园
第十七章: 自定义View程序中所有的可视对象要么是window,要么是view.在这一章中,你将创建一个NSView的子类. 随着时间的推移,你一般会需要创建自定义的view来完成自定义画图和事件响应.即使你没有打算这样做,你也应该通过学习创建view类来了解cocoa的内部工作机制
window是NSWindow的对象.每个window都会有多个views,每个view描述window中的一个矩形区域. view负责该区域的画图动作以及鼠标事件响应. view也可以响应键盘消息. 你以及和多个view的子类打过交道了: NSButton, NSTextField,NSTableView,和NSColorWell 都是view (注意,window不是NSView的子类)
View的层次view是按一定层次关系组织(如图17.1) .window包含了一个叫做content view的view.该view填满了整个window内部区域[除去title bar. 你可以在NSWindow类中找到contentView 和 setContentView方法] 通常,content view会有自己的子view.而这些子view有会有自己的子view.一个view知道自己的父view和子view,并知道自己所属的窗口 [到NSView类声明中,找找和它们相关的方法]
找到了么?&&&&- (NSView *)&&&&- (NSArray *)&&&&- (NSWindow *)
任何类型的view [这么说是指 view的子类,如NSButton,NSTableView...]都可以包含多个子view.不过对于大部分类型的view,我们不会给它添加子view. 下面5中类型view通常有子view1. window的content view2. NSBox. box中的内容就是它的子view3. NSScrollView. scroll view中包含的view就是它的子view. scroll bar也是它的子view4. NSSplitView. SplitView中的view就是它的子view 如图 17.2
5. NSTabView.&&当用户点选不同的tab时. 不同的子view交替切换如图17.3
-- 让一个View画自己 --在本节中,将创建一个简单的view. 它将自己刷成绿色.就像17.4 [灰色的..呵呵]
新建一个Cocoa Application工程, 命名为ImageFun. 点选File-&New file菜单,创建一个Objective-C NSView子类.命名为StretchView.
--创建一个View 子类的对象--打开MainMenu.nib. 从Library中拖一个CustomView(view&cell-&Layout View)放置在window上.如图17.5
将view大小改变接近window. 然后打开info panel. 将它的类设置成为StretchView.如图17.6
--大小检查--StretcView对象是window content view的子view. 这就有个有意思的问题:当父view改变大小的时候, view有什么反应呢?在info panel中有一个tab页面来指定这样的行为. 打开Size Info Panel. 设置如图17.7. 现在你改变窗口大小. view的大小会跟着变化了.
-- drawRect--当一个view需要刷新显示时,它将会收到drawRect:的消息,参数为一个需要重画的矩形区域, 这个方法会被自动调用-你不需要直接在代码中调用. 如果你需要让一个view重画,可以调用方法setNeedsDisplays[myView setNeedsDisplay:YES];
该方法将myView设置成"脏"的. 在事件处理中,myView将被重画
[cocoa , 系统]在调用drawView:前, 会对这个view lock focus. 每一个view都有自己的graphics context-包含了view的坐标系统,当前颜色,当前字体等. 当view被lock focus,它的graphics context将激活,而当unlock focus后,它的graphics context将不是激活状态. 任何时候的draw命令都是在当前激活的graphics context进行 [对于Mac的画图draw, 可以看看Quarz 2D . graphics context也是它里面的概念咯. 其实cocoa view 画图也是通过Quarz 2D来实现, 要对屏幕显卡进行绘制,那么就要有一个绘制环境,这个环境也就是graphics context , cocoa 中在每个view中保存了一个各自的graphics context . 绘制到那个view时就将它的graphics context设置为当前Quarz用来绘制的graphics context - 通过lock focus]
你可以使用NSBezierPath来绘制线条,圆形,曲线和矩形. 你可以使用NSImage来在view上绘制合成图像. 在本节例子中, 绘制一个绿色的矩形
打开StretchView.m. 添加如下代码- (void)drawRect:(NSRect)rect{&&&&NSRect bounds = [self bounds];&&&&[[NSColor greenColor] set];&&&&[NSBezierPath fillRect:bounds];}
如图17.10, NSRect结构由两个成员组成:origin - NSPoint类型, 和size - NSSize类型
NSSize结构有两个成员: width和height(都是float类型)NSPoint结构有两个成员:x和y(都是float类型)
因为性能的原因,Objective-C类中很少使用到结构. 你有可能用到的一些cocoa结构: NSPoint,NSRect,NSRange,NSDecimal 和NSAffineTransformStruct等等. NSRange描述区间. NSDecimal描述数字精度, NSAffineTransformStruct描述图形线性变换
注意,view通过bounds知道自己的位置. 在drawRect中得到bounds区域,将当前color设置为绿色,再使用当前色来填充整个bounds区域
通过参数传递的NSRect描述了这个view需要重画的"脏"的区域.它有可能会小于整个view的大小.如果绘制比较费时间的东西,可以只对该脏的区域进行重新绘制
setNeedsDisplay:将激发view整个可见区域重画. 如果需要激发view某个指定区域进行重话可以使用setNeedsDisplayInRect:NSRect dirtyRdirtyRect = NSMakeRect(0, 0, 50, 50);[myView setNeedsDisplayInRect:dirtyRect];
编译运行程序.试着改变window的大小看看
-- 使用NSBezierPath绘制--如果想绘制线条,曲线或多边形,可以使用NSBezierPath. 前面,你使用了NSBezierPath的fillRect 类方法来给view上色.在这节中你将使用NSBezierPath绘制随机点间的线条如图17.11
首先你需要一个成员变量来保存NSBezierPath对象.并创建一个方法来返回随机点. 在StretchView.h中修改如下#import &Cocoa/Cocoa.h&
@interface StretchView : NSView{&&&&NSBezierPath *}- (NSPoint)randomP
@end在StretchView.m中,重载initWithFrame方法-这是NSView的designated initializer[还记得它吧] . 它会在view对象创建时自动调用[在这个例子中,是在nib文件加载是cocoa调用]. 修改StretchView.m 在initWithFrame中,创建了一个path对象#import "StretchView.h"
@implementation StretchView
- (id)initWithFrame:(NSRect)rect{&&&&if (![super initWithFrame:rect])&&&&&&&&
&&&&// Seed the random number generator&&&&srandom(time(NULL));
&&&&// Create a path object&&&&path = [[NSBezierPath alloc] init];&&&&[path setLineWidth:3.0];&&&&NSPoint p = [self randomPoint];&&&&[path moveToPoint:p];&&&&&&&&for (i = 0; i & 15; i++) {&&&&&&&&p = [self randomPoint];&&&&&&&&[path lineToPoint:p];&&&&}&&&&[path closePath];&&&&}- (void)dealloc{&&&&[path release];&&&&[super dealloc];}// randomPoint returns a random point inside the view- (NSPoint)randomPoint{&&&&NSP&&&&NSRect r = [self bounds];&&&&result.x = r.origin.x + random() % (int)r.size.&&&&result.y = r.origin.y + random() % (int)r.size.&&&&}
- (void)drawRect:(NSRect)rect{&&&&NSRect bounds = [self bounds];
&&&&// Fill the view with green&&&&[[NSColor greenColor] set];&&&&[NSBezierPath fillRect: bounds];
&&&&// Draw the path in white&&&&[[NSColor whiteColor] set];&&&&[path stroke];}
@end编译运行程序,怎么样?酷吧! 好了,现在用[path fill] 代替[path stroke]看看,有什么不一样?
-- NSScrollView--在美术世界里,在同样的质量下,绘制的越大就越美观啊. 你的view很漂亮了.不过能不能让它更大一点呢., 你需要将它放置在scroll view中如图17.12
scroll view由3个部分组成: document view, content view,和scroll bar. 在本例中.你的view将成为document view,并显示在content view中-它是NSClipView的对象
虽然这个看上去复杂,其实很容易办到. 实际上都不需要添加代码. 打开mainmenu.nib文件,选中view.&&从LayOut 菜单中选择Embed Objects in Scroll View如图17.13
当window改变大小时,你希望scroll view跟着改变,而document view确不改变. 打开Size Inspector, 选择Scroll view. 设置他的Size Inspector,这样它就跟着window改变了如图17.14
注意view的长和宽双击scroll view内部,选中document view.你可以看到这是inspecotr的标题变成 Stretch View Size. 将view的大小修改为scroll view的2倍. 同时绑定左下角并不要跟随改变大小如图17.15. 编译运行程序
-- 通过程序创建View--你可以在Interface Builder中实例化多个view. 有时候,你会需要通过程序来创建view.例如,假定你希望在window上创建一个buttonNSView *superview = [window contentView];NSRect frame = NSMakeRect(10, 10, 200, 100);NSButton *button = [[NSButton alloc] initWithFrame:frame];[button setTitle:@"Click me!"];[superview addSubview:button];[button release];
--思考:cells--NSControl从NSView继承得到. 因为view有自己的graphics context. 这让view成为一个大,高价的类. 当初,在提供NSButton类时, 有人要编写一个计算器程序, 他第一件事就是创建10行10列的NSButton. 这样就有100个view别创建,效率是相当低啊. 后来,有人想到了一个聪明的主意: 将NSButton的大脑移到另外一个类[大脑? 就是button的主要功能了](不再是view类).并创建一个大的view(叫做NSMatrix). 用来装那100个button大脑. 我们把这个button 大脑内叫 NSButtonCell [这个就如设计原则所说,内的聚合咯,少用继承,多用聚合,看到好处了] 如图17.16
到最后,NSButton就是一个简单的view再加上它的大脑 NSButtonCell. button cell做了所有事情,而NSButton只是window上的一块绘制区域如图17.17
同样的.NSSlider就是一个包含了NSSliderCell的view.&&NSTextField 就是一个包含了NSTextFieldCell 的view.&NSColorWell, 抱歉,它没有cell :)
你拖一个control到window上,然后选择Embed Objects In -& Martix. 这样就创建了一个NSMatrix. 可以按住Option拖动martix 来设定它的行列数.如图17.18
NSMatrix 有一个Target和action. Cell也有target和action. 如果cell点击,cell的target ,action将激发,如果cell没有设置它的target 和action.那么matirx的target,acton将激发.
在处理matirx时,你常常要面对这样的问天,哪个cell激活?cell也可以设置它的tag- (IBAction)myAction:(id)sender {&&&&id theCell = [sender selectedCell];&&&&int theTag = [theCell tag];&&&&...}
cell的tag可以通过Interface Builder来设定
-- 思考: isFlipped --PDF和PostScript使用的是标准的迪卡尔坐标系统.当向上移动页面时,y值增加. Quartz使用了同样的模型. view的原点在左下点.
对于有些绘制,如果让原点在左上方会更方便. 也就是当向下移动页面是y增加,这时我们叫这个view是filpped的
你通过重载方法ifFlipped来filp一个view- (BOOL)isFlipped{&&&&return YES;}
当我们讨论坐标系统时, x和y是使用点来计数的. 一般72点=1英寸. 默认的1.0point及时屏幕上的一个像素.不过,你可以通过改变坐标系统来改变point的大小// Make everything in the view twice as largeNSSize newSnewScale.width = 2.0;newScale.height = 2.0;[myView scaleUnitSquareToSize:newScale];[myView setNeedsDisplay:YES];
-- 挑战 --NSBezierPath可以会在Bezier曲线. 绘制看看咯.(请查看NSBezierPath帮助文档)ios如何在 mac 应用程序中设置的自定义视图 (NSView) 的背景色?
注意事项: 本文中文内容可能为机器翻译,如要查看英文原文请点击上面连接.
我有试着改变 NSView 的背景颜色,这样在 iOS 中,
self.titleview.backgroundcolor = [UIColor redColor];
但没有这样的属性存在,所以在它以后,我试过,
self.titleBarView.layer.backgroundColor = [[NSColor redColor]set];
但它显示一些错误。
解决方法 1:
self.titleBarView.layer.backgroundColor = [NSColor redColor].CGC
如果你不想要使用 view.layer。在 NSView,您可以使用 NSBox (与自定义的样式)。NSBox 具有填充颜色的属性。图像处理(38)
MacOSX Dev(55)
iOSX Dev(311)
程序中所有的可视对象要么是window,要么是view.在这一章中,你将创建一个NSView的子类. 随着时间的推移,你一般会需要创建自定义的view来完成自定义画图和事件响应.即使你没有打算这样做,你也应该通过学习创建view类来了解cocoa的内部工作机制
window是NSWindow的对象.每个window都会有多个views,每个view描述window中的一个矩形区域. view负责该区域的画图动作以及鼠标事件响应. view也可以响应键盘消息. 你以及和多个view的子类打过交道了: NSButton, NSTextField,NSTableView,和NSColorWell 都是view (注意,window不是NSView的子类)
View的层次
view是按一定层次关系组织(如图17.1) .window包含了一个叫做content view的view.该view填满了整个window内部区域[除去title bar. 你可以在NSWindow类中找到contentView 和 setContentView方法] 通常,content view会有自己的子view.而这些子view有会有自己的子view.一个view知道自己的父view和子view,并知道自己所属的窗口 [到NSView类声明中,找找和它们相关的方法]
&&&&- (NSView *)
&&&&- (NSArray *)
&&&&- (NSWindow *)
任何类型的view [这么说是指 view的子类,如NSButton,NSTableView...]都可以包含多个子view.不过对于大部分类型的view,我们不会给它添加子view. 下面5中类型view通常有子view
1. window的content view
2. NSBox. box中的内容就是它的子view
3. NSScrollView. scroll view中包含的view就是它的子view. scroll bar也是它的子view
4. NSSplitView. SplitView中的view就是它的子view 如图 17.2
5. NSTabView.&&当用户点选不同的tab时. 不同的子view交替切换如图17.3
-- 让一个View画自己 --
在本节中,将创建一个简单的view. 它将自己刷成绿色.就像17.4 [灰色的..呵呵]
新建一个Cocoa Application工程, 命名为ImageFun. 点选File-&New file菜单,创建一个Objective-C NSView子类.命名为StretchView.
--创建一个View 子类的对象--
打开MainMenu.nib. 从Library中拖一个CustomView(view&cell-&Layout View)放置在window上.如图17.5
将view大小改变接近window. 然后打开info panel. 将它的类设置成为StretchView.如图17.6
--大小检查--
StretcView对象是window content view的子view. 这就有个有意思的问题:当父view改变大小的时候, view有什么反应呢?在info panel中有一个tab页面来指定这样的行为. 打开Size Info Panel. 设置如图17.7. 现在你改变窗口大小. view的大小会跟着变化了.
-- drawRect--
当一个view需要刷新显示时,它将会收到drawRect:的消息,参数为一个需要重画的矩形区域, 这个方法会被自动调用-你不需要直接在代码中调用. 如果你需要让一个view重画,可以调用方法setNeedsDisplays
[myView setNeedsDisplay:YES];
该方法将myView设置成&脏&的. 在事件处理中,myView将被重画
[cocoa , 系统]在调用drawView:前, 会对这个view lock focus. 每一个view都有自己的graphics context-包含了view的坐标系统,当前颜色,当前字体等. 当view被lock focus,它的graphics context将激活,而当unlock focus后,它的graphics context将不是激活状态. 任何时候的draw命令都是在当前激活的graphics context进行 [对于Mac的画图draw, 可以看看Quarz 2D . graphics
context也是它里面的概念咯. 其实cocoa view 画图也是通过Quarz 2D来实现, 要对屏幕显卡进行绘制,那么就要有一个绘制环境,这个环境也就是graphics context , cocoa 中在每个view中保存了一个各自的graphics context . 绘制到那个view时就将它的graphics context设置为当前Quarz用来绘制的graphics context - 通过lock focus]
你可以使用NSBezierPath来绘制线条,圆形,曲线和矩形. 你可以使用NSImage来在view上绘制合成图像. 在本节例子中, 绘制一个绿色的矩形
打开StretchView.m. 添加如下代码
- (void)drawRect:(NSRect)rect
&&&&NSRect bounds = [self bounds];
&&&&[[NSColor greenColor] set];
&&&&[NSBezierPath fillRect:bounds];
如图17.10, NSRect结构由两个成员组成:origin - NSPoint类型, 和size - NSSize类型
NSSize结构有两个成员: width和height(都是float类型)
NSPoint结构有两个成员:x和y(都是float类型)
因为性能的原因,Objective-C类中很少使用到结构. 你有可能用到的一些cocoa结构: NSPoint,NSRect,NSRange,NSDecimal 和NSAffineTransformStruct等等. NSRange描述区间. NSDecimal描述数字精度, NSAffineTransformStruct描述图形线性变换
注意,view通过bounds知道自己的位置. 在drawRect中得到bounds区域,将当前color设置为绿色,再使用当前色来填充整个bounds区域
通过参数传递的NSRect描述了这个view需要重画的&脏&的区域.它有可能会小于整个view的大小.如果绘制比较费时间的东西,可以只对该脏的区域进行重新绘制
setNeedsDisplay:将激发view整个可见区域重画. 如果需要激发view某个指定区域进行重话可以使用setNeedsDisplayInRect:
NSRect dirtyR
dirtyRect = NSMakeRect(0, 0, 50, 50);
[myView setNeedsDisplayInRect:dirtyRect];
编译运行程序.试着改变window的大小看看
-- 使用NSBezierPath绘制--
如果想绘制线条,曲线或多边形,可以使用NSBezierPath. 前面,你使用了NSBezierPath的fillRect 类方法来给view上色.在这节中你将使用NSBezierPath绘制随机点间的线条
首先你需要一个成员变量来保存NSBezierPath对象.并创建一个方法来返回随机点. 在StretchView.h中修改如下
#import &Cocoa/Cocoa.h&
@interface StretchView : NSView
&&&&NSBezierPath *
- (NSPoint)randomP
在StretchView.m中,重载initWithFrame方法-这是NSView的designated initializer[还记得它吧] . 它会在view对象创建时自动调用[在这个例子中,是在nib文件加载是cocoa调用]. 修改StretchView.m 在initWithFrame中,创建了一个path对象
#import &StretchView.h&
@implementation StretchView
- (id)initWithFrame:(NSRect)rect
&&&&if (![super initWithFrame:rect])
&&&&// Seed the random number generator
&&&&srandom(time(NULL));
&&&&// Create a path object
&&&&path = [[NSBezierPath alloc] init];
&&&&[path setLineWidth:3.0];
&&&&NSPoint p = [self randomPoint];
&&&&[path moveToPoint:p];
&&&&for (i = 0; i & 15; i++) {
&&&&&&&&p = [self randomPoint];
&&&&&&&&[path lineToPoint:p];
&&&&[path closePath];
- (void)dealloc
&&&&[path release];
&&&&[super dealloc];
// randomPoint returns a random point inside the view
- (NSPoint)randomPoint
&&&&NSRect r = [self bounds];
&&&&result.x = r.origin.x + random() % (int)r.size.
&&&&result.y = r.origin.y + random() % (int)r.size.
- (void)drawRect:(NSRect)rect
&&&&NSRect bounds = [self bounds];
&&&&// Fill the view with green
&&&&[[NSColor greenColor] set];
&&&&[NSBezierPath fillRect: bounds];
&&&&// Draw the path in white
&&&&[[NSColor whiteColor] set];
&&&&[path stroke];
编译运行程序,怎么样?酷吧! 好了,现在用[path fill] 代替[path stroke]看看,有什么不一样?
-- NSScrollView--
在美术世界里,在同样的质量下,绘制的越大就越美观啊. 你的view很漂亮了.不过能不能让它更大一点呢., 你需要将它放置在scroll view中如图17.12
scroll view由3个部分组成: document view, content view,和scroll bar. 在本例中.你的view将成为document view,并显示在content view中-它是NSClipView的对象
虽然这个看上去复杂,其实很容易办到. 实际上都不需要添加代码. 打开mainmenu.nib文件,选中view.&&从LayOut 菜单中选择Embed Objects in Scroll View如图17.13
当window改变大小时,你希望scroll view跟着改变,而document view确不改变. 打开Size Inspector, 选择Scroll view. 设置他的Size Inspector,这样它就跟着window改变了如图17.14
注意view的长和宽
双击scroll view内部,选中document view.你可以看到这是inspecotr的标题变成 Stretch View Size. 将view的大小修改为scroll view的2倍. 同时绑定左下角并不要跟随改变大小如图17.15. 编译运行程序
-- 通过程序创建View--
你可以在Interface Builder中实例化多个view. 有时候,你会需要通过程序来创建view.例如,假定你希望在window上创建一个button
NSView *superview = [window contentView];
NSRect frame = NSMakeRect(10, 10, 200, 100);
NSButton *button = [[NSButton alloc] initWithFrame:frame];
[button setTitle:@&Click me!&];
[superview addSubview:button];
[button release];
--思考:cells--
NSControl从NSView继承得到. 因为view有自己的graphics context. 这让view成为一个大,高价的类. 当初,在提供NSButton类时, 有人要编写一个计算器程序, 他第一件事就是创建10行10列的NSButton. 这样就有100个view别创建,效率是相当低啊. 后来,有人想到了一个聪明的主意: 将NSButton的大脑移到另外一个类[大脑? 就是button的主要功能了](不再是view类).并创建一个大的view(叫做NSMatrix). 用来装那100个button大脑.
我们把这个button 大脑内叫 NSButtonCell [这个就如设计原则所说,内的聚合咯,少用继承,多用聚合,看到好处了] 如图17.16
到最后,NSButton就是一个简单的view再加上它的大脑 NSButtonCell. button cell做了所有事情,而NSButton只是window上的一块绘制区域如图17.17
同样的.NSSlider就是一个包含了NSSliderCell的view.&&NSTextField 就是一个包含了NSTextFieldCell 的view.&NSColorWell, 抱歉,它没有cell :)
你拖一个control到window上,然后选择Embed Objects In -& Martix. 这样就创建了一个NSMatrix. 可以按住Option拖动martix 来设定它的行列数.如图17.18
NSMatrix 有一个Target和action. Cell也有target和action. 如果cell点击,cell的target ,action将激发,如果cell没有设置它的target 和action.那么matirx的target,acton将激发.
在处理matirx时,你常常要面对这样的问天,哪个cell激活?cell也可以设置它的tag
- (IBAction)myAction:(id)sender {
&&&&id theCell = [sender selectedCell];
&&&&int theTag = [theCell tag];
cell的tag可以通过Interface Builder来设定
-- 思考: isFlipped --
PDF和PostScript使用的是标准的迪卡尔坐标系统.当向上移动页面时,y值增加. Quartz使用了同样的模型. view的原点在左下点.
对于有些绘制,如果让原点在左上方会更方便. 也就是当向下移动页面是y增加,这时我们叫这个view是filpped的
你通过重载方法ifFlipped来filp一个view
- (BOOL)isFlipped
&&&&return YES;
当我们讨论坐标系统时, x和y是使用点来计数的. 一般72点=1英寸. 默认的1.0point及时屏幕上的一个像素.不过,你可以通过改变坐标系统来改变point的大小
// Make everything in the view twice as large
NSSize newS
newScale.width = 2.0;
newScale.height = 2.0;
[myView scaleUnitSquareToSize:newScale];
[myView setNeedsDisplay:YES];
-- 挑战 --
NSBezierPath可以会在Bezier曲线. 绘制看看咯.
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:262029次
积分:3802
积分:3802
排名:第5865名
原创:45篇
转载:492篇
评论:11条
(5)(5)(2)(6)(4)(1)(4)(3)(2)(3)(17)(29)(6)(35)(30)(8)(5)(1)(5)(8)(17)(3)(7)(25)(45)(2)(12)(2)(13)(1)(8)(2)(19)(24)(18)(8)(3)(5)(1)(1)(5)(31)(26)(3)(24)(11)(17)(3)(11)(9)

我要回帖

更多关于 nsview 背景图片 的文章

 

随机推荐