I created an NSImageView using code:
@implementation IconView
-(void)awakeFromNib {
[self setImageRect:NSMakeRect(36, 66, 144, 144)];
[self setImageView:[[NSImageView alloc] initWithFrame:[self imageRect]]];
[self addSubview:[self imageView]];
//For the frame around the image:
[self setFrameRect:NSMakeRect(18, 42, 180, 180)];
[NSBezierPath setDefaultLineWidth:12];
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
[[self alertColor] set];
[NSBezierPath strokeRect:[self frameRect]];
[[[self imageView] image] setSize:[self imageRect].size ];
}
And I set the NSImageView's image like this:
@implementation IconViewController
-(void)setColor:(NSColor *)color forApplication:(NSRunningApplication *)app {
IconView* iconView = (IconView*)[self view]; //The view associated with this controller
[iconView setAlertColor:color];
[[iconView imageView] setImage:[app icon]];
NSLog(@"app icon: %@", [app icon]);
[[self view] setNeedsDisplay:YES];
}
The log output is this:
2015-05-07 22:29:27.711 HelloApplication[1569:17913] app icon: <NSImage 0x608000260c00 Size={32, 32} Reps=(
"<NSIconRefImageRep:0x608000083bb0 iconRef=0x103 size:128x128 pixels:128x128>",
"<NSIconRefImageRep:0x608000083d90 iconRef=0x103 size:128x128 pixels:256x256>",
"<NSIconRefImageRep:0x608000083e30 iconRef=0x103 size:256x256 pixels:256x256>",
"<NSIconRefImageRep:0x608000083de0 iconRef=0x103 size:256x256 pixels:512x512>",
"<NSIconRefImageRep:0x608000084150 iconRef=0x103 size:512x512 pixels:512x512>",
"<NSIconRefImageRep:0x608000084100 iconRef=0x103 size:48x48 pixels:48x48>",
"<NSIconRefImageRep:0x608000084790 iconRef=0x103 size:36x36 pixels:36x36>",
"<NSIconRefImageRep:0x608000084ec0 iconRef=0x103 size:36x36 pixels:72x72>",
"<NSIconRefImageRep:0x608000084470 iconRef=0x103 size:32x32 pixels:32x32>",
"<NSIconRefImageRep:0x608000085000 iconRef=0x103 size:32x32 pixels:64x64>",
"<NSIconRefImageRep:0x608000085050 iconRef=0x103 size:18x18 pixels:18x18>",
"<NSIconRefImageRep:0x608000084fb0 iconRef=0x103 size:18x18 pixels:36x36>",
"<NSIconRefImageRep:0x6080000850a0 iconRef=0x103 size:16x16 pixels:16x16>",
"<NSIconRefImageRep:0x6080000850f0 iconRef=0x103 size:16x16 pixels:32x32>",
"<NSIconRefImageRep:0x608000085140 iconRef=0x103 size:512x512 pixels:1024x1024>"
)>
So, it looks like I have an NSImage--but it won't display. I see the stroke of the frameRect in the proper color, but no image displays. IB shows that in IconView.xib my IconViewController(File's Owner) is connected to the IconView:
My window controller does this:
//
// MyWindowController.m
// HelloApplication
//
@implementation MyWindowController
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
- (void)setUpView {
[self setViewCtrl:[[IconViewController alloc] initWithNibName:@"IconView" bundle:nil]];
…
…
NSView* view = [[self viewCtrl] view];
[[self window] setContentSize:[view bounds].size]; //[view bounds] returns a struct, whose elements must be
[[self window] setContentView:view]; //accessed with dot notation.
…
}
-(id) initWithWindowNibName:(NSString *)windowNibName {
if (self = [super initWithWindowNibName:windowNibName]) {
[self setUpView];
}
return self;
}
@end
My AppDelegate does this:
//
// AppDelegate.m
// HelloApplication
//
#import "AppDelegate.h"
#import "MyWindowController.h"
@interface AppDelegate ()
@property(strong) MyWindowController* windowCtrl;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self setWindowCtrl:[[MyWindowController alloc] initWithWindowNibName:@"MainWindow"]];
[[self windowCtrl] showWindow:self];
}
If you need more files or screenshots let me know:
//
// IconView.h
// HelloApplication
//
#import <Cocoa/Cocoa.h>
@interface IconView : NSView
@property(copy) NSColor* alertColor;
@property(weak) NSImageView* imageView;
@end
...
//
// IconView.m
// HelloApplication
//
#import "IconView.h"
@interface IconView()
@property(assign) NSRect frameRect;
@property(assign) NSRect imageRect;
-(void)awakeFromNib;
@end
@implementation IconView
-(void)awakeFromNib {
[self setImageRect:NSMakeRect(36, 66, 144, 144)];
[self setImageView:[[NSImageView alloc] initWithFrame:[self imageRect]]];
[self addSubview:[self imageView]];
[self setFrameRect:NSMakeRect(18, 42, 180, 180)];
[NSBezierPath setDefaultLineWidth:12];
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
[[self alertColor] set];
[NSBezierPath strokeRect:[self frameRect]];
[[[self imageView] image] setSize:[self imageRect].size ];
}
@end
...
//
// IconViewController.h
// HelloApplication
//
#import <Cocoa/Cocoa.h>
#import "MyActivityMonitorDelegateProtocol.h"
@interface IconViewController : NSViewController <MyActivityMonitorDelegateProtocol>
@end
...
//
// IconViewController.m
// HelloApplication
//
#import "IconViewController.h"
#import "IconView.h"
@interface IconViewController ()
-(void)setColor:(NSColor*)color forApplication:(NSRunningApplication*)app;
@end
@implementation IconViewController
-(void)setColor:(NSColor *)color forApplication:(NSRunningApplication *)app {
IconView* iconView = (IconView*)[self view]; //The view associated with this controller
[iconView setAlertColor:color];
[[iconView imageView] setImage:[app icon]];
NSLog(@"app icon: %@", [app icon]);
[[self view] setNeedsDisplay:YES];
}
-(void)applicationDidLaunch:(NSRunningApplication *)app {
[self setColor:[NSColor greenColor] forApplication:app];
}
-(void)applicationDidTerminate:(NSRunningApplication *)app {
[self setColor:[NSColor redColor] forApplication:app];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do view setup here.
}
@end
This is an example from an old cocoa book, p 240-241:
Cocoa Programming: A Quick Start Guide for Developers.
Response to @Joshua Nozzi's answer:
(1)
-drawRect:
— Don't set properties here, least of all, something that causes further drawing in subviews (such as setting your image view's image).
I’m actually just setting the size of the ImageView’s image. The example I was following dutifully removed any code from drawRect:
that only needed to be called once, but when I try setting the size of the NSImageView's image elsewhere, e.g. in the IconViewController's viewDidLoad:
method, it doesn't succeed in setting the displayed image's size, so it must happen too late. Ah, it works if I set the size in the IconViewController’s setColor:forApp:
method right before telling the view it needs to be redrawn:
-(void)setColor:(NSColor *)color forApplication:(NSRunningApplication *)app {
IconView* iconView = (IconView*)[self view]; //The view associated with this controller
NSImageView* imageView = [iconView imageView];
[iconView setAlertColor:color];
[imageView setImage:[app icon] ];
//NSLog(@"app icon: %@", [app icon]);
[ [imageView image] setSize:[iconView imageRect].size ];
[[self view] setNeedsDisplay:YES];
}
(2)
Your call to -setupView comes during your window controller's initialization, but your [window's] nib hasn't been loaded yet...
It looks like these are the lines that concern you:
- (void)setUpView {
…
…
[[self window] setContentSize:[view bounds].size]; //[view bounds] returns a struct, whose elements must be
[[self window] setContentView:view]; //accessed with dot notation.
Calling [[self window] doSomething]
before the window is unarchived means that [self window]
will be nil
, and calling [nil doSomething]
won’t do anything. I moved those lines into the Window controller’s windowDidLoad
method:
@implementation MyWindowController
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
NSView* view = [[self viewCtrl] view];
[[self window] setContentSize:[view bounds].size]; //[view bounds] returns a struct, whose elements must be
[[self window] setContentView:view]; //accessed with dot notation.
}
And it seems there may be other errors as well: I’ve read that you shouldn’t call accessor methods in init methods--instead you should access the ivars directly.
(3)
You appear to have application delegate methods (did launch / did terminate) in your icon view controller
No, I don’t think that is the case; the tutorial I’m following used those confusing method names. I kept thinking they were Cocoa methods so often myself that I actually put a comment in my code indicating they were custom methods. Here is the declaration of the IconViewController:
@interface IconViewController : NSViewController <MyActivityMonitorDelegateProtocol>
And applicationDidLaunch:
/applicationDidTerminate:
are the methods declared by MyActivityMonitorDelegateProtocol
. The application in the method names actually refers to any application that is launched/terminated on my system while my app is running.