View Full Version : Cocoa: How to get app to fire mouseDown on _any_ part of window?

Jun 16, 2009, 04:51 PM
Hi All,

In the app I'm building, I'd like to have a HUD panel pop up over my main user interface when certain conditions occur but I don't want to require the user to click an 'OK' button to dismiss it. Instead, I'd prefer to have the panel disappear when the user clicks anywhere within the app. If I put the "orderOut" code within a mouseDown event, it only fires when I click in the narrow blank areas around the controls, since most of the area is covered by a split panel and an ImageView. Is there any way to tell the other controls to pass the mouse click along to the underlying window -- or perhaps just interpret the next mouse click as a 'dismiss' command?

BTW -- I'm also having a little trouble with closing the HUD panel with the "X" close button: The first time the panel comes up, I can close it with the "X" but the second time the "X" does nothing.


P.S. Please don't hesitate to tell me if this is a dumb approach and not the "Mac Way". I've used interface devices like this in other contexts and rather like them but I'll accepted other suggestions.

Jun 16, 2009, 05:43 PM
You could maybe put up an invisible (fully transparent) child window over your main window (or HUD panel) which tracks and duplicates its frame and position, and have it intercept mouse events.

Jun 16, 2009, 06:24 PM
Thanks HiRez.

Actually, not too long after I posted, a similar thought occurred to me. I use the technique of graying out the window in some of my browser-based apps so if I can do what you suggest and make the child window semi-transparent, it'd serve nicely. Then, instead of a HUD panel, I could center my message on the window in a text control. Hmmm. Much simpler. Gonna try it!

-- Mark

Jun 16, 2009, 08:09 PM
In UIKit this is very easy, you just make a button that covers the whole screen. Make it "custom" so it has no appearance, and then drag it to the background in the hierarchal viewer. Or choose menu option "Send to Back".

I haven't written much of anything in Cocoa, I much prefer UIKit, but hopefully there is a similar technique.

Jun 17, 2009, 09:08 AM
Okay -- I've achieved what I intended (or close enough). Here's how:

1. Add an outlet to the controller class:
IBOutlet NSButton * btnGrayedOut;
2. Add a Square Button to your window and connect it to the outlet. You should also go into the Button Size tab on the Inspector and click all of the arrows in the "Autosizing" section so that it sizes in all dimensions.

3. Add an action to the controller and connect it to the button as well:
- (IBAction)ClickedGrayedOutButton:(id)sender;
4. Add a "GrayOut" method to do the work of sizing and displaying the button:

- (void)GrayOut: (NSString *) message; {
NSRect frame;
float fadeIn;

//*** Get the frame rectangle of the main window
frame = [[self window] frame];

//*** Expand the button to cover the entire area of the window
[btnGrayedOut setFrame: NSMakeRect(0, 0, frame.size.width, frame.size.height)];
//*** Set title text and show
[btnGrayedOut setTitle: message];
[btnGrayedOut setHidden: NO];
//*** Make it fade in
for (fadeIn=0.0; fadeIn<0.6; fadeIn+=.02) {
[btnGrayedOut setAlphaValue: fadeIn];
[btnGrayedOut display];

- (IBAction)ClickedGrayedOutButton:(id)sender; {
[btnGrayedOut setHidden: YES];

Now, when you call "GrayOut" . . .

[self GrayOut: @"NO DOCUMENT ON SCANNER"];

. . . the button will fade in and cover the entire window with the text you specify in the center. If the user clicks anywhere on the window, it'll dismiss the message.


-- Mark

Jun 17, 2009, 04:41 PM
Nice solution! Thanks for sharing the code, I'm sure it'll come in handy some day.

Jun 17, 2009, 05:34 PM
Another possible solution would be to use [NSWindow nextEventMatchingMask:untilDate:inMode:dequeue:] with NSLeftMouseDownMask to wait until the next mouse click event.