Need help getting an NSStatusItem with a custom view to respond to mouse clicks

Discussion in 'Mac Programming' started by br-, Oct 19, 2006.

  1. br- macrumors member

    Joined:
    Aug 7, 2006
    #1
    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.
     
  2. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #2
    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.
     
  3. br- thread starter macrumors member

    Joined:
    Aug 7, 2006
    #3
    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.
     
  4. HiRez macrumors 603

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #4
    Hmm, well try sending them a message if they left an email address?
     
  5. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #5
    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.
     
  6. br- thread starter macrumors member

    Joined:
    Aug 7, 2006
    #6
    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?
     
  7. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #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 ...
     
  8. br- thread starter macrumors member

    Joined:
    Aug 7, 2006
    #8
    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.
     
  9. kainjow Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #9
    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? :)
     
  10. br- thread starter macrumors member

    Joined:
    Aug 7, 2006
    #10
    Makes sense to me. Thanks for your help. :)
     
  11. br- thread starter macrumors member

    Joined:
    Aug 7, 2006
    #11
    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.
     

Share This Page