Reputation: 297
Im trying to call an IBAction Method in two classes that is called whenever a button that I created in interface builder is clicked. What I really want to happen is for a NSRect to appear whenever the button is clicked but the button and the place where I want the NSRect to appear are in separate views, so the button is in View A and the destination for the rect is in View B. I have tried doing this with NSNotificationCenter but it did not work.
Upvotes: 0
Views: 1013
Reputation: 46028
You are missing the C in MVC. Cocoa uses the Model-View-Controller design pattern and you seem to be missing a controller.
You should create a controller class (possibly a subclass of NSWindowController
so that it is responsible for the window) that implements an action method such as -buttonPressed:
which is connected to your button. The controller should manage the model (which in this case is whatever the rectangles represent) such that when you press the button, the model is updated. The controller should then make your rectangle view redraw itself.
Your rectangle view should be set up so that it implements a datasource pattern (see the NSTableView
datasource implementation for a good example) so that it knows how many and where to draw the rectangles. If you set your controller as the view's datasource, your view doesn't need to know anything about the model.
Your rectangle view should be set up something like this:
RectangleView.h: @protocol RectangleViewDataSource;
@interface RectangleView : NSView
@property (weak) id <RectangleViewDataSource> dataSource;
@end
//this is the data source protocol that feeds the view
@protocol RectangleViewDataSource <NSObject>
- (NSUInteger)numberOfRectsInView:(RectangleView*)view;
- (NSRect)rectangleView:(RectangleView*)view rectAtIndex:(NSUInteger)anIndex;
@end
RectangleView.m:
@implementation RectangleView
@synthesize dataSource;
- (void)drawRect:(NSRect)rect
{
//only draw if we have a data source
if([dataSource conformsToProtocol:@protocol(RectangleViewDataSource)])
{
//get the number of rects from the controller
NSUInteger numRects = [dataSource numberOfRectsInView:self];
for(NSUInteger i = 0; i < numRects; i++)
{
NSRect currentRect = [dataSource rectangleView:self rectAtIndex:i];
//draw the rect
NSFrameRect(currentRect);
}
}
}
@end
You would assign your controller as the datasource of the view and make it implement the RectangleViewDataSource
protocol methods.
The controller would look something like this:
YourController.h:
#import "RectangleView.h"
@interface YourController : NSWindowController <RectangleViewDataSource>
@property (strong) NSMutableArray* rects;
@property (strong) IBOutlet RectangleView *rectView;
- (IBAction)buttonPressed:(id)sender;
@end
YourController.m:
@implementation YourController
@synthesize rects;
@synthesize rectView;
- (id)init
{
self = [super init];
if (self)
{
rects = [[NSMutableArray alloc] init];
}
return self;
}
- (void)awakeFromNib
{
//assign this controller as the view's data source
self.rectView.dataSource = self;
}
- (IBAction)buttonPressed:(id)sender
{
NSRect rect = NSMakeRect(0,0,100,100); //create rect here
[rects addObject:[NSValue valueWithRect:rect]];
[self.rectView setNeedsDisplay:YES];
}
//RectangleViewDataSource methods
- (NSUInteger)numberOfRectsInView:(RectangleView*)view
{
return [rects count];
}
- (NSRect)rectangleView:(RectangleView*)view rectAtIndex:(NSUInteger)anIndex
{
return [[rects objectAtIndex:anIndex] rectValue];
}
@end
Upvotes: 2
Reputation: 237110
You want to have a controller that knows about the view with the rects. Hook the button up to the controller. When the button is pressed, add a rect.
Upvotes: 1
Reputation: 9392
Are they in separate windows? If they aren't, just declare an IBAction in your ViewB and connect it to the button in ViewA. If they are in different windows, the NSNotificationCenter way should work. Did you use postNotificationName:
and addObserver:selector:name:object
with the same notification name?
Upvotes: 1