Open and close NSWindow with NSButton through NSWindowController? - objective-c

I've got a custom NSButton that I'm actually sticking in an NSStatusItem. When the NSButton is clicked, it launches my window. When the NSButton is clicked again, the window should close.
If the window is open, it appears as if the NSButton stops responding (or doesn't receive) click events! Here's the relevant code:
[statusItem setView:myCustomButton];
[myCustomButton setAction:#selector(showWindow:)];
- (void)showWindow:(id)sender {
if(!myWindowController) {
myWindowController = [[MyWindowController alloc] initWithWindowNibName:#"MyWindow"];
}
[myWindowController showWindow:statusItem];
[myWindowController.window orderFront:nil];
}
Am I doing something crazy? If I set a breakpoint in the above, it is hit when the button is clicked the first time but is not hit when the button is clicked again.

I'm guessing that you're not setting a target on the button. If a button has an action but no target, it gets sent up the responder chain. When the new window is shown, the responder chain is probably being changed, which means your action is being sent to a different place.
tl;dr: try setting a target on the button.

Related

Opening a modal dialog (modal window or sheet) from another modal dialog

I need to open a modal window, which can open another modal window (or sheet). First window works fine, but second behaves strange.
This is how I open first window:
RegisterDialog * registerDialog=[[RegisterDialog alloc] initWithWindowNibName:#"RegisterDialogMac"];
NSWindow* window = [registerDialog window];
[NSApp runModalForWindow:window];
This window behaves properly and responds to any buttons, I just added a bit of code to stop modal event loop after pressing on a red button:
- (void)windowWillClose:(NSNotification *)notification {
[[NSApplication sharedApplication] stopModal];
}
Ok. Now I am opening the second dialog window if user press the "Register" button:
-(IBAction)registerPressed:(id)sender {
RegistrationDialogMac* registrationDialog=[[RegistrationDialogMac alloc] initWithWindowNibName:#"RegistrationDialogMac"];
NSWindow* window = [registrationDialog window];
[NSApp runModalForWindow:window];
}
This second dialog window works fine too, but is closed only if to press red button.
This is how "Cancel" button is processed:
-(IBAction)cancelPressed:(id)sender {
[NSApp stopModal];
[[self window] close];
}
After pressing it modal event loop is stopped, first dialog window becomes active, but second window still remains here. It is closed only if I press the red button. This is strange, as the first modal window is closed properly by the same code.
Ok. I tried to go different route and run the second dialog window as a sheet:
-(IBAction)registerPressed:(id)sender {
RegistrationDialogMac* registrationDialog=[[RegistrationDialogMac alloc] initWithWindowNibName:#"RegistrationDialogMac"];
NSWindow* window = [registrationDialog window];
[self.window beginSheet: window
completionHandler:^(NSModalResponse returnCode) { }
];
}
(I turned off "Visible at launch" to correctly draw this sheet attached to the first dialog window)
This way the second dialog window is drawn, but ignores all button presses. Graphically buttons are pressed, but aren't processed. This code:
-(IBAction)cancelPressed:(id)sender {
NSLog(#"!");
[[self window] close];
//[NSApp endSheet:[self window]]; // may be this would be correct way to close sheet? Don't know as this method isn't run anyway
}
isn't executed at all, there is no a single "!" character in the log.
So I am doing something wrong. I actually almost have no any Mac coding experience, only Windows.
Found that [self window] of the second dialog was nil, so it couldn't respond to close. Checked the .xib - and, yes, I forgot to connect the window outlet to the window itself. Fixed, and the window is closed correctly now.
This doesn't fix the problem of unresponding buttons when this second dialog is drawn as Sheet though.

How to close a new window in macOS development?

I am new to macOS application development.
I have a main window and a custom window called ImageSetter, both have windowcontroller.
In the main window, I have a button, whose action is to open a new window by:
ImageSetter *anImageSetter = [[ImageSetter alloc] initWithWindowNibName:#"ImageSetter"];
[anImageSetter showWindow:self];
On the window of ImageSetter, I want to attach a button, whose function is to close the ImageSetter window. I tried to use
[aButton setTarget:self];
[aButton setAction:#selector(closeItself)];
and
- (void)closeItself{
[self.window close];
}
in the implementation of ImageSetter.
But I figured that I can't close it by using that button.
Help!
Thanks.
First of all, a standard window already has a button to close it in the title bar. If at all possible, you should use the standard controls.
If you have a button in a window, and all you want that button to do is close its window, simply send the performClose: message up the responder chain:
// [aButton setTarget:nil/* first responder */]; -- already nil, nothing to set
[aButton setAction:#selector(performClose:)];
The button will send the -performClose: message to the first object in the responder chain that implements to that message, which in your case should be the window that contains the button.
If you want to be explicit about the target, you can set it directly:
[aButton setTarget:aButton.window];

How to detect when a NSPanel closes as a result of losing focus? E.g. A user clicking outside of the NSPanel (Window?)

I have a generic NSPanel window that I am using as a preferences window in my app. I have a selector that I call every time the window closes. The purpose of that selector is to save the state of the users chosen preferences (there is no "save" button).
I have an NSButton ("CLOSE") which I easily setup to call my closing selector.
I set it up so that my selector is also called when the user clicks the RED X in the top left corner of the NSPanel by doing:
NSButton *closeButton = [[self window] standardWindowButton:NSWindowCloseButton];
[closeButton setTarget:self];
[closeButton setAction:#selector(myCloseSelector:)];
This works perfectly. My problem though? The window also closes if the user clicks outside of the NSPanel. E.g. If they take their mouse and click on their browser window below the NSPanel that popped up. This also closes the window.
How do I catch my NSPanel losing focus and closing ? I need to ensure that when this happens I also get my selector called.
Thanks!
Made my NSWindowController a delegate for NSWindowDelegate.
myWindowController.h
#interface myWindowController : NSWindowController <NSWindowDelegate>
and then set myWindowController as the delegate for my NSPanel.
Now I can implement:
- (void) windowDidResignKey:(NSNotification *)notification {
NSLog(#"Houston...we lost a panel.");
}
and everything works swimmingly!

Close window programmatically

For a Cocoa application on a Mac I need ti display some windows when the use click on the associated button. I can display the window using this :
-(void)popView:(NSString *)viewName {
_windowController = [[NSWindowController alloc] initWithWindowNibName:viewName];
[_windowController showWindow:nil];
}
In the new window I have a Push Button "Cancel" and Another "Save". I want to perform some queries in a database when the "Save" button is pressed and close the window when the "Cancel" button is pressed.
I can close the window while dragin it from the xib file (The "outlet menu" when you right-click on the window)
But I can't use this for the "Save" button.
I tried [self performSelector:#selector(performClose:)]; but I got an error message :
[AddProductViewController performClose:]: unrecognized selector sent
to instance 0x107f64900
Same for [[[self view] window] close];
I lack of ideas how to solve it, this is my very first Mac application.

How to open a window on click on NSStatusItem?

I'm pretty new to cocoa, so please excuse me for any stupid mistakes I make.
I have a NSStatusItem, which I want to use to open up a menu. However as far as I know and have heard across different forms, without a custom view you are restricted to just a pop down menu. Is this true? And if so how do you make a custom view to do something (e.g. open a window in my case)? Thanks for any help.
No, it is not true. You need to set up the target and action for the status item to call a method which does what you want (opens the window).
// This goes where you set up the status item
NSStatusItem *statusItem; // You need to get this from the status bar
[statusItem setTarget:self];
[statusItem setAction:#selector(openWindow:)];
// This method is called when the status item is clicked
- (void)openWindow:(id)sender {
NSWindow *window = [self window]; // Get the window to open
[window makeKeyAndOrderFront:nil];
}
You may also want to call [NSApp activateIgnoringOtherApps:nil]; to your openWindow: method to ensure that the window you open is not behind some other application's window.