How to respond to _one_ click on a control in a cocoa window that is not key? - macos

I have a button in a child window.
If I am working in the parent window (it is key), and I click once on the button in the child window, this click makes the child window key. I then have to click a second time to make the control (in this case, a button) respond.
How can I immediately respond to a click on that button in a non-key window?

This is controlled individually for each view class by -[NSView acceptsFirstMouse:] which returns NO by default. Subclasses have to return YES to allow the first click to work.
However, NSButton implementation already returns YES so it should work as is, unless your button is not painted by NSButton instance.

Related

Close borderless floating NSWindow on click outside

I want to create a borderless window floating above the main window. The main window should be the key window (I want it to handle the keyboard and mouse events). Also, the floating window should close as the user clicks outside of it. Basically, I'm creating a very custom context menu, just like NSMenu. It should behave likewise.
So I created my window this way:
NSWindow *menuWindow = [NSWindow windowWithContentViewController:menuViewController];
menuWindow.styleMask = NSBorderlessWindowMask;
menuWindow.level = NSFloatingWindowLevel;
[menuWindow makeKeyAndOrderFront:self];
That works perfectly, but how do I handle clicks outside to close it? The window doesn't invoke delegate's windowDidResignKey, because it's not a key window. If it does overload canBecomeKeyWindow (so that it returns YES), then the floating window grabs the user input, which is not what I want.
So, is there any way to automatically close a borderless window? Can NSPanel help? I tried using it, but with no success (the becomesKeyOnlyIfNeeded selector doesn't do what I need).
To detect clicks outside the window but within your app, you could install an event monitor using +[NSEvent addLocalMonitorForEventsMatchingMask:handler:]. If you also want to close the window when the user clicks in a different app, you could observe the NSApplicationDidResignActiveNotification notification.
NSWindow has a property hidesOnDeactivate that should do this for you.
From the Apple Docs:
The value of this property is true if the window is removed from the
screen when its application is deactivated; false if it remains
onscreen. The default value for NSWindow is false; the default value
for NSPanel is true.

How to auto-activate cocoa window so you don't need to click twice?

I have two windows: A main window and an inspector panel. Both have sliders and draggable items.
You have to click twice every time you work in the other window. First click activates the window. Second click allows a drag to start.
Is it possible to have a click in a window automatically activate it AND allow the event to pass through to the controls so you don't need to do it twice all the time when switching between an inspector panel and main window?
The first thing to try is to set the panel's becomesKeyOnlyIfNeeded property to true. That way, you main window will remain key even if the user clicks and drags on controls within the panel.
Otherwise, you have to handle this in each different view class. A view should override -acceptsFirstMouse: to return true if it wants to handle the same mouse event that activates the window. For custom view classes, this is straightforward. If you're using standard controls and they don't already implement -acceptsFirstMouse: to return true, you'll need to subclass them and use those subclasses instead.

How do I stop my NSbutton from being selected when the app starts by default?

I created a button, and a have a little problem: When the my app launches, the button is selected. How do I disable this selection?
Example:
Caveat: This answer is incomplete: It just hides the focus ring (without preventing the selection). There's little benefit in this solution.
Set your button's focus ring type to none:
[myButton setFocusRingType:NSFocusRingTypeNone];
You can also set this option in the XIB.
First, you should know that, by default, buttons can't get focus. A user would have to have selected System Preferences > Keyboard > Shortcuts > Full Keyboard Access: All Controls. If they've done that, they may want a button to initially have focus.
Anyway, the proper way to do this is to call [theWindow makeFirstResponder:nil] sometime after showing it the first time. When to do this depends on exactly how the window gets shown. If you show it explicitly in code, then you can make the call just after that. If it's shown because its Visible at Launch flag is set in its NIB, then you'd do it after the NIB is loaded. Etc.
Something should always be first responder in a window, if anything can be. Normally, only a few controls like text fields can become first responder, but when a user has Full Keyboard Access enabled, it's normal for a button to be selected by default.
If you don't want this particular button to start selected, set the window's initialFirstResponder to another control.
I'd advise against using -[NSWindow makeFirstResponder:nil]. The window will start with nothing selected, but the button will become selected as soon as the user hits tab. This is unusual for Mac apps because there's no way to get the window back into the "nothing selected" state as a user.

combobox dropdown window can show beyond the combobox window,how?

in windows, how can make a 'child' window beyond the parent window, and the parent window always in active status (GetActiveWindow() return parent), just like the combobox dropdown window.
I think these are the main points when trying to do this:
The pop-up is a top-level window which has the same parent as the control. (i.e. The pop-up is not a child of the control. It's not a child-window at all; it's a top-level window, but one without a thick window border etc. so it doesn't look like a normal top-level window.) That's why it can extend outside of the control's boundaries.
When the pop-up is created it is shown using ShowWindow(hWndPopup, SW_SHOWNA) so that it does not take the input focus. This prevents the parent window from going inactive.
When the pop-up is created you capture the mouse using SetCapture. You then track where the mouse is and highlight items within the pop-up when the mouse overlaps them. When the mouse button is clicked you act on whatever is under the mouse (or cancel the pop-up if the mouse isn't over it at all). Remember to respond to WM_CAPTURECHANGED, in case something else captures the mouse. And remember to ReleaseCapture when you are done.
The popup should handle WM_MOUSEACTIVATE by returning MA_NOACTIVATEANDEAT.

How to make a keyboard shortcut to close dialog with Xcode/Interface Builder?

This seems awfully basic but here goes. If you are keyboard-oriented you get used to using Command-W to close windows all the time in OS X. I'd like to add that capability to the dialogs I am creating in Interface Builder for my program. I can see how to add a keyboard equivalent to a button action but what if I don't have a button?
Should I add an invisible button and put the shortcut on that? Seems clunky. Surely there is just some method I can override but what I've tried so far isn't working.
When you press Command + W, it's the exact same as choosing File -> Close from the menu bar. What Close does is send a performClose: message to the first responder. That, in turn, will check if the receiver or if the receiver's delegate implements windowShouldClose:, and the window will close if it returns YES (otherwise, it will call the close method).
So really, it depends on what type of dialog you've got here. If it's non-modal (essentially, if you can access the menu bar while it's running) and is an instance or subclass of NSWindow, then all you need to do is override the windowShouldClose: method in your dialog's delegate (or your dialog class, if you subclassed NSWindow or something) and make it return YES.
However, if the dialog is a modal dialog (you can't access the menu bar, switch windows, etc. while the dialog is running), then you can't do it this way. You could add an invisible button, but in all honesty, a modal dialog should not be closed by hitting Command-W, for that most certainly violates some Apple interface guideline out there. (Especially since, as Ande noted, it's standard practice to have Esc close/cancel a dialog.)
Adding an invisible button works just fine.
Is the dialog an NSWindow? Because by default the File->Close menu option is set to the performClose: action of the first responder, and already wired to command-w
If the dialog isn't a window simply make your dialog first responder and implement the performClose: action.
why don't you try this:
-(void)keyDown:(NSEvent *)theEvent{
//If the key is X or x it just closes the window
if ([theEvent.characters.uppercaseString isEqualToString:#"X"]) {
[self.window performClose:self];
}
}
or if you want to show a window you can instanciate and show it there instead of the performClose
Jasper was right about the code part. For interface builder(storyboard), there is a quick fix:
In your storyboard, hit "CMD+Shift+L" to bring up the components lib, select File Menu Item.
Add the file menu item to the Application Scene's Main Menu Node. (Remove unwanted file menus)
Now you have a keyboard shortcut to close a window.

Resources