Re: Updating menu items in a status bar item
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.