Search code examples
objective-cdelegatestarget-action

Mouse events handlers


MyNSImageView is a subclass of NSImageView, here I have:

@interface MyNSImageView : NSImageView 
{
}
@end

@implementation MyNSImageView

//- (void) mouseDown: (NSEvent *) theEvent 
//{
//  do not wish to implement mouseDown event handler from here
//}
@end

In another class called MainView, I have:

@interface MainView : NSView 
{
    MyNSImageView *ImageView1;
    MyNSImageView *ImageView2;

}
@end

- (void)awakeFromNib
{
    ImageView1 = [[[MyNSImageView alloc] initWithFrame:NSMakeRect(5, 5, 240, 240)] autorelease];
    NSImage* image1 = [[[NSImage alloc] initWithContentsOfFile: @"/Volumes/MAC DAT2/pictures/MP6107.jpg"] autorelease];
    [ImageView1 setImage:image1];
    [self addSubview:ImageView1];

    ImageView2 = [[[MyNSImageView alloc] initWithFrame:NSMakeRect(300, 5, 240, 240)] autorelease];
    image1 = [[[NSImage alloc] initWithContentsOfFile: @"/Volumes/MAC DAT2/pictures/MP5784.jpg"] autorelease];
    [ImageView2 setImage:image1];
    [self addSubview:ImageView2];
}

- (void) mouseDown2: (NSEvent *) theEvent 
{
    NSLog(@"mousedown2 from MainView");
}
- (void) mouseDown1: (NSEvent *) theEvent 
{
    NSLog(@"mousedown1 from MainView");
}
@end

- (void) mouseDown: (NSEvent *) theEvent 
{
    NSLog(@"mousedown from MainView");
}

In the MainView, when I click on the ImageView1 or ImageView2, I would like to have the mouseDown1 or mouseDown2 method to handle the event accordingly not the mouseDown method.

I have read about target/action/delegate and responder stuff, but still could not see the exact syntax to do this.


Solution

  • One way to handle this is with a delegate:

    First you declare a delegate protocol for your NSImageView subclass:

    @class MyNSImageView;
    @protocol MyNSImageViewDelegate <NSObject>
    
    - (void)myImageView:(MyNSImageView *)view mouseDown:(NSEvent *)event;
    
    @end
    
    
    @interface MyNSImageView : NSImageView {
    
    }
    // declare the delegate member
    @property (assign) id<MyNSImageViewDelegate> delegate;
    @end
    
    @implementation MyNSImageView
    @synthesize delegate = _delegate;
    
    // In your mouseDown method, notify the delegate
    - (void)mouseDown:(NSEvent *)event {
        if([self.delegate respondsToSelector:@selector(myImageView:mouseDown:)]) {
            [self.delegate myImageView:self mouseDown:event];
        }
    }
    
    @end
    

    Then, declare your MainView class to implement the MyNSImageViewDelegate protocol:

    @interface MainView : NSView <MyNSImageViewDelegate> {
        MyNSImageView *imageView1;
        MyNSImageView *imageView2;
    }
    @end
    

    And in your MainView implementation:

    - (void)awakeFromNib {
        // create your image views then add our instance as the delegate to each
        ImageView1.delegate = self;
        ImageView2.delegate = self;
    }
    
    // here we implement the `MyNSImageViewDelegate` method, which will get 
    // called when any `MyImageNSView` instance we've added ourselves as
    // delegate to gets clicked.
    - (void)myImageView:(MyNSImageView *)view mouseDown:(NSEvent *)event {
        if (view == imageView1) {
            NSLog(@"imageView1 clicked");    
        } else if (view == imageView2) {
            NSLog(@"imageView2 clicked");    
        }
    }