• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Updating menu items in a status bar item
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Updating menu items in a status bar item


  • Subject: Re: Updating menu items in a status bar item
  • From: Jeffrey Mattox <email@hidden>
  • Date: Sun, 9 Feb 2003 04:06:25 -0600

With Daniel's help on this and some other details, I got the status bar menu items to update dynamically, at the moment the menu is selected. It took a lot of trial and error -- I guess I'm the monkey who typed something useful.

For the record, here's what works:

NSMenu *theStatusMenu; // the menu object (preset with dummy menu items)

- (void)menuClicked:(NSObject *)theStatusBarButton
{
NSWindow *theWindow;
NSView *theView;
NSRect contentRect = NSMakeRect( 0, 0, 100, 100 ); // x, y, w, h
NSRect theBoxBounds = NSMakeRect( 0, 0, 100, 100 );
NSRect screenRect;

NSLog(@"menuClicked start...\n");
screenRect = [[NSScreen mainScreen] frame]; // get the screen height
NSPoint mouseLocation = [NSEvent mouseLocation];
mouseLocation.x = mouseLocation.x - 25; // move left a bit
mouseLocation.y = screenRect.size.height - 25; // just below the bar

theWindow = [[NSWindow alloc] initWithContentRect:contentRect
styleMask:NSBorderlessWindowMask backing:NSBackingStoreNonretained
defer:NO];

theView = [[NSView alloc] initWithFrame:theBoxBounds]; // create
[theWindow setContentView:theView]; // put into the window
[theView setFrame:theBoxBounds]; // reposition

NSEvent* theEvent = [NSEvent mouseEventWithType:NSLeftMouseUp
location:mouseLocation
modifierFlags:0
timestamp:[NSDate timeIntervalSinceReferenceDate]
windowNumber:[theWindow windowNumber]
context:[NSGraphicsContext currentContext]
eventNumber:1
clickCount:1
pressure:1.0];

// set the menu items (titles, etc.,) of theStatusMenu here...
// e.g., [[theStatusMenu itemAtIndex:0] setTitle:@"testing"];
// then pop it up...

[NSMenu popUpContextMenu:theStatusMenu withEvent:theEvent forView:theView];
[theWindow autorelease];
[theView autorelease];
NSLog(@"menuClicked done\n");
return;
}


Notes:

1. The status item doesn't have a view, so I create an invisible window and a view (the size and location don't appear to matter).

2. I position the popup by taking the mouse location and moving it left a little and just below the status bar. It looks exactly like the real popup (which actually drops down). I have not bothered to keep it from going too far left so I'm not sure what happens when if it hangs over the right edge of the screen.

3. You can use a menu created in Cocoa or AppleScript Studio. However, I've had intermittent problems with the menus generating AS errors when selected (sometimes my application worked, sometimes it didn't), so I made all of my actions point to Cocoa methods. However, the menu can still be designed in IB and only its object id needs to be passed to Cocoa from AS at runtime.

4. In this example, I have preset theStatusMenu with several menu items (using AppleScript Studio and IB), but it could be constructed using Cocoa, right there were it's needed.

5. theWindow and theView need to be released somewhere. I'm not certain they should be autoreleased as shown above. The popUpContextMenu method does not return until a menu item is selected, so I thinks it's safe.

6. Read the other implementation details in my original post, below.

So, there you have it. As often happens when learning this Mac stuff by trial and error, I feel like the monkey who finally produced something intelligent.

Jeff
"Man always wins in the end."


At 9:22 AM -0800 2/5/03, Daniel Jalkut wrote:
Hi Jeffrey - I have also been plagued by this "shortcoming" of the way menus are displayed. As far as I can tell (including setting breakpoints on postNotification and examining all notes that take place while clicking menus), there is no suitable notification for when a menu is about to display.

The general advise from Apple engineers seems to be that you should achieve your goal of a dynamic menu by implementing the "validateMenuItem:" method in whatever object is the target for your menu items. Unfortunately, this suggestion doesn't seem to do the trick so well when you want to be able to wholesale destroy and rebuild a menu before it is displayed. We really want something like a "validateMenu:" method instead.

So  I think your approach is probably a good one, to simply bypass the usual path to displaying a menu. As far as I know the only "legitimate" way to display a menu in an arbitrary place at an arbitrary time is by using the +popUpContextMenu class method of NSMenu to display the menu. You will probably have to make up a bogus Event object for the method so that you can cause the menu to display exactly where you want it to (regardless of where in your status item the click occurred).

Hope this helps. Yes, it's tedious and obnoxious. In general, the "menu customization" situation seems to be an ugly spot on Cocoa's otherwise easy-to-modify class structure. This is probably due to the replacement of some of Cocoa's menu handling classes (where you could otherwise add custom functionality) with direct call-through to Carbon menu manager implementations.

Cheers,
Daniel

On Wednesday, February 5, 2003, at 12:58 AM, Jeffrey Mattox wrote:

I have a NSStatusItem on the systemStatusBar that contains a NSMenu and several NSMenuItems. When I click on the status bar item, I see the menu items drop down from the status bar. So, I've proved to myself that I can create a drop down menu and I can select the items within it.

My problem is that my menu item titles are dynamic, and I won't know what they should be until the moment the status bar item is clicked. So, to get control when the status bar item is clicked, I don't do this (see why, below):

[theStatusBarItem setMenu:theMenu]

instead I do this:

[theStatusBarItem setAction:@selector(menuClicked:)];
[theStatusBarItem sendActionOn:NSLeftMouseDownMask];

and, sure enough, menuClicked runs when I click on the status bar item. In this case, however, the menu items do not appear (there aren't any because I skipped the setMenu:, as I must do according to the documentation for the NSStatusBar's setAction: method).

So, in menuClicked, I construct a menu and set the menu item titles, and then I need to cause them to be displayed. But, I can't figure out how to do that. If I do setMenu: there, they don't appear unless I release the mouse and click again.

What I need is a notification that the status bar is about to display the menu. Then I could still use setMenu early on, and simply set my menu item titles just before they are displayed. However, no such notification exists for the status bar.

So, I'm stuck. When I click on the status bar item, either I see my menu items, but the titles are stale, or I get control in order to set the titles, but the menu items don't appear.

Any ideas?

Jeff
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.

References: 
 >Re: Updating menu items in a status bar item (From: Daniel Jalkut <email@hidden>)

  • Prev by Date: Re: Programmatically adding an NSTextField to an NSTextView
  • Next by Date: All Keys
  • Previous by thread: Re: Updating menu items in a status bar item
  • Next by thread: Re: NSTask/NSPipe STDIN hangs on large data...
  • Index(es):
    • Date
    • Thread