Cocoa / Objective-C: Draw Rectangle on Button Click
Categories:
Drawing Rectangles on Button Click in Cocoa/Objective-C

Learn how to dynamically draw a rectangle on a custom view in a Cocoa application using Objective-C, triggered by a button click.
In Cocoa applications, drawing custom shapes and graphics often involves overriding the drawRect:
method of an NSView
subclass. This article will guide you through the process of creating a simple macOS application where clicking a button triggers the drawing of a rectangle on a dedicated drawing area. We'll cover setting up the UI, creating a custom view, and implementing the drawing logic.
Setting Up the Project and UI
First, let's set up a new Cocoa application project in Xcode and design a basic user interface. We'll need a window, a button, and a custom view where our rectangle will be drawn. The custom view will be the canvas for our drawing operations.
1. Create a New Xcode Project
Open Xcode and create a new project. Choose 'macOS' -> 'App' and select 'Cocoa App' as the template. Name your project (e.g., 'RectangleDrawer') and ensure 'Language' is set to 'Objective-C'.
2. Design the User Interface
Open MainMenu.xib
(or Main.storyboard
if you're using storyboards). Drag a Push Button
and a Custom View
from the Object Library onto your main window. Resize the custom view to be a prominent drawing area. Connect the button's IBAction
to your AppDelegate
or a new ViewController
.
3. Create a Custom NSView Subclass
Create a new Objective-C class, subclassing NSView
. Name it DrawingView
. This will be our custom drawing canvas. In MainMenu.xib
, select your Custom View
and change its class in the Identity Inspector to DrawingView
.
flowchart TD A[Start Xcode Project] --> B{Choose Cocoa App Template} B --> C[Design UI in MainMenu.xib] C --> D[Add Push Button] C --> E[Add Custom View] E --> F[Set Custom View Class to DrawingView] D --> G[Connect Button Action] F --> H[Implement Drawing Logic in DrawingView] G --> I[Trigger Redraw on Button Click] H --> J[End]
Project Setup Workflow for Drawing a Rectangle
Implementing the Drawing Logic in DrawingView
The core of our drawing functionality will reside in the DrawingView
class. We'll override its drawRect:
method to perform the actual drawing. To make the drawing dynamic, we'll introduce a property to control whether the rectangle should be drawn.
// DrawingView.h
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
@interface DrawingView : NSView
@property (nonatomic, assign) BOOL shouldDrawRectangle;
@end
NS_ASSUME_NONNULL_END
// DrawingView.m
#import "DrawingView.h"
@implementation DrawingView
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
if (self.shouldDrawRectangle) {
NSRect rectToDraw = NSMakeRect(50, 50, 100, 80);
[[NSColor blueColor] setFill];
NSRectFill(rectToDraw);
[[NSColor redColor] setStroke];
NSBezierPath *path = [NSBezierPath bezierPathWithRect:rectToDraw];
[path setLineWidth:3.0];
[path stroke];
}
}
// When shouldDrawRectangle changes, we need to tell the view to redraw
- (void)setShouldDrawRectangle:(BOOL)shouldDrawRectangle {
_shouldDrawRectangle = shouldDrawRectangle;
[self setNeedsDisplay:YES]; // Mark the view as needing redrawing
}
@end
[super drawRect:dirtyRect];
at the beginning of your drawRect:
implementation to ensure proper view hierarchy drawing. The setNeedsDisplay:YES
method is crucial for triggering a redraw when your drawing state changes.Connecting the Button to the Drawing View
Finally, we need to connect our button's action to update the shouldDrawRectangle
property of our DrawingView
instance. This will cause the view to redraw itself and display the rectangle.
1. Create an IBOutlet for DrawingView
In your AppDelegate.h
(or ViewController.h
), create an IBOutlet
for your DrawingView
. For example: @property (nonatomic, weak) IBOutlet DrawingView *drawingCanvas;
.
2. Connect IBOutlet in Interface Builder
Go back to MainMenu.xib
. Control-drag from your AppDelegate
(or ViewController
) to the DrawingView
and connect it to the drawingCanvas
outlet.
3. Implement the Button Action
In your AppDelegate.m
(or ViewController.m
), implement the IBAction
method connected to your button. Inside this method, toggle the shouldDrawRectangle
property of your drawingCanvas
.
// AppDelegate.h (or ViewController.h)
#import <Cocoa/Cocoa.h>
#import "DrawingView.h"
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (nonatomic, weak) IBOutlet DrawingView *drawingCanvas;
- (IBAction)drawRectangleButtonClicked:(id)sender;
@end
// AppDelegate.m (or ViewController.m)
#import "AppDelegate.h"
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
- (IBAction)drawRectangleButtonClicked:(id)sender {
// Toggle the drawing state
self.drawingCanvas.shouldDrawRectangle = !self.drawingCanvas.shouldDrawRectangle;
NSLog(@"Button clicked! Rectangle drawing state: %d", self.drawingCanvas.shouldDrawRectangle);
}
@end
Now, when you run the application and click the button, the drawRectangleButtonClicked:
method will be invoked. This method toggles the shouldDrawRectangle
property of your DrawingView
. Because setShouldDrawRectangle:
calls setNeedsDisplay:YES
, the DrawingView
will be marked for redrawing, and its drawRect:
method will be called, either drawing or clearing the rectangle based on the property's state.