Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

br-

macrumors member
Original poster
Aug 7, 2006
32
0
I have an NSStatusItem with an IB generated custom view (set using setView:). My problem is that the NSStatusItem doesn't accept any mouse clicks. It acts like it's a static image.

I've tried using the following method, But when I click the status item, it never gets called.
Code:
-(void)mouseDown:(NSEvent *)event
{
	NSLog(@"Mouse event recieved");
}

I've also tried setting actions on some of the items in the view. They, too, never get called when clicked.

Anyone know how to get this working? Thanks.
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,629
Western US
Does your NSStautusItem have a menu attached to it? I think they are meant to have menu attached, and I think I remember reading something about them automatically entering a menu tracking modal loop when clicked upon, which could be the reason the mouse down event is getting hijacked on the way to your view's overridden mouseDown: method. Unfortunately, I do not have a solution for you if you're trying for a "menuless" status item, I don't believe Apple wants you to have that functionality there.
 

br-

macrumors member
Original poster
Aug 7, 2006
32
0
The NSStatusItem doesn't have a menu attached. In fact, once you set a custom view on a NSStatusItem, you can't use any of the NSStatusItem methods involving menus.

Anyway, I'm pretty sure that this is possible. There are programs out there that do this. Also, I've read threads where people have said that they've recieved clicks successfully. Unfortunately, they didn't post any code detailing how it was done.
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,629
Western US
br- said:
I've read threads where people have said that they've recieved clicks successfully. Unfortunately, they didn't post any code detailing how it was done.
Hmm, well try sending them a message if they left an email address?
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
I just created a sample project to test this. It worked fine for me.

I initialized the status item like so:
Code:
_statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:22] retain];
[_statusItem setView:[[[View alloc] init] autorelease]];
And then setup my View class like so:
Code:
- (void)drawRect:(NSRect)rect
{
	[[NSColor redColor] set];
	NSRectFill(rect);
}

- (void)mouseDown:(NSEvent *)event
{
	NSLog(@"mouseDown");
}
And mouseDown gets logged.
 

br-

macrumors member
Original poster
Aug 7, 2006
32
0
It seems like it might have something to do with me making my custom view in Interface Builder instead of coding a NSView subclass in Xcode.

What I'm thinking might work is making a category for my IB generated Custom View that implements mouseDown:. I gave it a shot, but Xcode gave me errors indicating that it didn't know about the custom view I was trying to make a category for. The specific error is:
Code:
error: cannot find interface declaration for 'customView'

Here's the relevant code:

Code:
//AppController.h
#import <Cocoa/Cocoa.h>
#import "MenuView.h"

@interface AppController : NSObject 
{
	NSStatusItem *statusItem;
	..other variables..
@public
	IBOutlet NSView *customView;
}
Code:
//MenuView.h
#import <Cocoa/Cocoa.h>
#import "AppController.h"

@interface customView (MenuView)     //Error appears here

-(void)mouseDown:(NSEvent *)event

@end

Is what I'm trying to do even possible? Or am I missing something elementary?
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
Your view is a category of NSView, not a subclass. You need to subclass NSView and override mouseDown:.

Your View.h file should look like this:

Code:
@interface MyView : NSView ...
 

br-

macrumors member
Original poster
Aug 7, 2006
32
0
But then I can't use IB to put all the controls on the view, right? I'd have to do it all manually. I was thinking that by making a category, if possible, I'd be able to extend the IB generated custom view and override the mouseDown: method without coding the whole thing in a subclass.
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
No, you can still use IB to connect setup your view. But if you want to have your own custom mouseDown: behavior, you must create a subclass and override that method. A category doesn't work unless the class it's methods work on knows about it. So if you have a generic NSView category method, and a normal NSView class (not a subclass), the category method won't work. That is why you need to subclass NSView. ¿Comprende? :)
 

br-

macrumors member
Original poster
Aug 7, 2006
32
0
kainjow said:
No, you can still use IB to connect setup your view. But if you want to have your own custom mouseDown: behavior, you must create a subclass and override that method. A category doesn't work unless the class it's methods work on knows about it. So if you have a generic NSView category method, and a normal NSView class (not a subclass), the category method won't work. That is why you need to subclass NSView. ¿Comprende? :)

Makes sense to me. Thanks for your help. :)
 

br-

macrumors member
Original poster
Aug 7, 2006
32
0
I followed your advice, but I am still unable to get it to accept mouse down events. I'll explain my process just in case I messed up anywhere.

First, I made a header file for my NSView subclass:
Code:
//MenuView.h
#import <Cocoa/Cocoa.h>
#import "AppController.h"

@interface MenuView : NSView

-(void)mouseDown:(NSEvent *)event;
-(void)drawRect:(NSRect)rect;

@end

Then I changed the controller header file to indicate that the IBOutlet is now a MenuView object instead of an NSView:
Code:
//AppController.h
#import <Cocoa/Cocoa.h>
#import "MenuView.h"
@class MenuView;

@interface AppController : NSObject 
{
	NSStatusItem *statusItem;
	
      ...variables...
		
	IBOutlet MenuView *customView;	
}
Then I dragged MenuView.h over to Interface Builder and set the custom class of the View to be MenuView. Here's my implementation:
Code:
//MenuView.m
#import "MenuView.h"

@implementation MenuView

-(id)init
{
    if (self = [super init])
	{
	}	
    return self;
}

-(void)awakeFromNib
{
	NSLog(@"Awoken");
}

-(void)mouseDown:(NSEvent *)event
{
	NSLog(@"Mouse down");
}

-(void)drawRect:(NSRect)rect
{
	[[NSColor redColor] set];
	NSRectFill(rect);
}

-(void)dealloc
{
	[super dealloc];
}

@end
And I know this subclass works and gets used, because the NSStatusItem gets filled with red. However, mouseDown: never gets called and I'm at a loss as to why.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.