NSView 2
NSView 2
#import <Cocoa/Cocoa.h>
@interface StretchView:View
{
NSBezierPath *path;
}
- (NSPoint)randomPoint;
@end
Drawing with NSBezierPath
• Make StretchView.m look like this
#import “StretchView.h”
@implementation StretchView
- (id)initWithFrame:(NSRect)rect
{
int i;
NSPoint p;
- (void)drawRect:(NSRect)rect
{
NSRect bounds = [self bounds];
[[NSColor greenColor] set];
[NSBezierPath fillRect: bounds];
- (void)dealloc
{
[path release];
[super dealloc];
}
@end
and Voila!
Our Green View with random lines
NSScrollView
• Open MainMenu.nib in Interface Builder
• Select the view, and choose “Make subview of Scroll
View” from the layout menu
• Make the ScrollView resize with the window
• Change the StretchView NOT resize with window
• Save the nib an build the application and run
and Voila!
Our Scrollable Green View with random lines
Images and Mouse Events
NSResponder
• The previous application drew random interconnected
lines
• A more interesting application would be some sort of
drawing application
• To write this sort of application we need to be able to
get and handle mouse events
• All event of the event-handling methods are declared in
NSResponder
• The argument to all of NSResponders methods is always
an NSEvent
NSEvent
• An event object has all the information about what the
user did to trigger the event
• When dealing with mouse events, you will be interested
in the following methods:
– (NSPoint)locationInWindow
• This method returns the location of the mouse event
– (unsigned int)modifierFlags
• This integer tells you which modifier key the user is
holding down on the keyboard
• This enables the programmer to tell a control-click from
a shift-click
NSEvent
• The code would look like this:
- (void)mouseDown:(NSEvent *)e
{
unsigned int flags;
flags = [e modifierFlags];
if (flags & NSControlKeyMask) {
...handle control click...
}
if (flags & NSShiftKeyMask) {
...handle shift click...
}
}
NSEvent
• Here are the constants you will AND (&) against the
modifier flags:
– NSAlphaShiftKeyMask
– NSShiftKeyMask
– NSControlKeyMask
– NSAlternateKeyMask
– NSCommandKeyMask
– NSNumericPadKeyMask
– NSHelpKeyMask
– NSFunctionKeyMask
NSEvent
• more methods...
– (NSTimeInterval)timestamp
• This method gives the time interval in seconds between
the machine booted and the event
– (NSWindow *)window
• This method returns the window associated with the
event
– (int)clickCount
• Was it a single, double or tripe click
– (float)pressure
• If the user is using an input device that gives pressure *a
tablet) this method returns the pressure (between 0 and
1)
Getting Mouse Events
• To get mouse events, you need to override the mouse
event methods in StretchView.m
- (void)mouseDown:(NSEvent *)event
{
NSLog(@”mouseDown: %d , [event clickCount]);
}
- (void)mouseDragged:(NSEvent *)event
{
NSLog(@”mouseDragged: “);
}
- (void)mouseUp:(NSEvent *)event
{
NSLog(@”mouseUp”);
}
Getting Mouse Events
• Build and run your application
• Try double-clicking, dragging etc
Using NSOpenPanel
• It would be fun to composite an image onto the view
• First we need to create a controller object that will read
the image from a file
• This is a good opportunity to learn how to use
NSOpenPanel
NSOpenPanel
• Open the nib file and create a new subclass on NSObject
called AppController
• Create two outlets called “stretchView” (of type
StretchView) and “slider” (of type NSSlider)
• Create two actions “open:” and “fade:”
• Create files for the AppController class and add them to
your project
• Now instantiate a new instance of AppController
• Ctrl-drag from the AppController instance to the
StretchView and connect to the stretchView outlet
NSOpen
• Drop a slider on the window beneath the view
• In the inspector set its range from 0 to 1
• Also check the box labelled “Continuously send action
while sliding”
• Connect the slider outlet to the instance of NSSlider
• Set the target of the slider to be the AppController
• Its action will be fade:
• Delete all the menu items from the File menu except
Open
• Ctrl-drag to connect the menu item to the
AppControllers open: action
awakeFromNib Versus Init
• WHen your nib file is loaded three things will happen (in
this order) to the AppController object (and all other
objects in your nib)
– It will be allocated and sent the init method
– Its outlets will be set
– It will be sent awakeFromNib
• Note that init is sent before any of its outlets are set, so
we cannot send messages to any of the other objects
from the nib file in the init method
• We can however send them messages from the
awakeFromNib method
Edit the code
Edit AppController.h and add the following line
#import <Cocoa/Cocoa.h>
@class StretchView;
Edit the code
Edit AppController.m
#import “AppController.h”
#import “StretchView.h”
@implementation AppController
- (void)awakeFromNib
{
[slider setFloatvalue:0.5];
[stretchView setOpacity:0.5];
}
- (IBAction)fade:(id)sender
{
[stretchView setOpacity:[sender floatValue]];
}
Edit the code
continued...
- (void)openPanelDidEnd:(NSOpenPanel *)openPanel
returnCode:(int)returnCode
contextInfo:(void *)x
{
NSString *path
NSImage *image
- (IBAction)open:(id)sender
{
[panel beginSheetForDictionary:nil
file:nil
types:[NSImage imageFileTypes]
modaForWindow:[stretchView window]
modalDelegate:self
didEndSelector:@selector(openPanelDidEnd:reurnCode:contextInfo:)
contextInfo:NULL];
]
@end
Note
• Notice the line where we start the sheet
- (void)beginSheetForDirectory:(NSString *)path
file:(NSString *)name
types:(NSArray *)types
modalForWindow:(NSWindow *)docWindow
modalDelegate:(id)delegate
didEndSelector:(SEL)didEndSelector
contextInfo:(void *)contextInfo
- (void)openPanelDidEnd:(NSWindow *)sheet
returnCode:(int)returnCode
contextInfo:(void *)contextInfo;
#import <Cocoa/Cocoa.h>
@end
Composite an Image onto our View
Add to StretchView.m
- (void)setImage:(NSImage *)newImage
{
[newImage retain];
[image release];
image = newImage;
[self setNeedsDisplay:YES];
}
- (void)setOpacity:(float)x
{
opacity = x;
[self setNeedsDisplay:YES];
}
Composite an Image onto our View
continued...
- (void)drawRect:(NSRect)rect
{
NSRect bounds = [self bounds];
[[NSColor greenColor] set];
[NSBezierPath fillRect:bounds];
[[NSColor whiteColor] set];
[path stroke];
if (image) {
NSRect imageRect;
NSRect drawingRect;
imageRect.origin = NSZeroPoint;
imageRect.size = [image size];
drawingRect = imageRect;
[image drawInRect:imageRect
fromRect:imageRect
operation:NSCompositeSourceOver
fraction:opacity];
}
}
Note
• Notice that the drawRect:fromRect:operatio:fraction:
method composites the image onto the view
• The fraction determines the opacity
• Also remember to be tidy
- (void)dealloc
{
[image release];
[path release];
[super dealloc];
}
NSPoint downPoint;
NSPoint currentPoint;
- (void)mouseDragged:(NSEvent *)event
{
NSPoint p = [event locationInWindow];
currentPoint = [self convertPoint:p fromView:nil];
[[self superView] autoscroll:event];
[self setNeedsDisplay:YES];
}