Control behavior of window close button

I'm sure this is pretty basic, but I'm not even sure how to articulate my question to do a search.


When the user clicks on the red close button for a window in my app, I want to be able to control what happens. Specifically, I want it to call makeKeyAndOrderFront: on a different window.


It looks like I might need an NSWindowController, but beyond that I'm not sure what to do. Is there an easier way? Or is it even worth the trouble?

Posted on Aug 22, 2016 12:24 AM

Reply
5 replies

Aug 22, 2016 7:31 AM in response to stevejobsfan0123

Take a look at methods like -windowShouldClose: and -windowWillClose: in the NSWindowDelegate, they can be used to do stuff when a window closes. To use this you will typically use -setDelegate: to associate a delegate (i.e. a helper object) with the window to do certain actions on behalf of the window.


Using delegates allows you to customize the behavior of individual objects without having to create lots of one off sub classes. Delegates are a common Cocoa pattern and are used by many classes to allow customization of their behavior.

Aug 22, 2016 8:50 PM in response to hokanst

Ah, I've never used delegates before. Very interesting.


I created a subclass of NSWindowController and overrode the windowShouldClose: method. Now, I have never worked with raw Objective-C before, I've only used AppleScriptObjC. This is what I have; I suspect there is a simple syntax error:


- (BOOL)windowShouldClose:(id)sender {

[sender orderOut:(nil)];

[sender [parentWindow makeKeyAndOrderFront:(nil)]];

returntrue;

}

Aug 22, 2016 9:13 PM in response to stevejobsfan0123

Unfortunately, closing a window is anything but basic. It can be one of the most difficult things to do. If you aren't doing a true Document-based application, then it might be a little easier.


Generally, what you are describing is not good interface design. If the user want to close a window, they don't want another window opened. The only real side effect you should perform is closing the entire application if this is the last window open.


If you don't already know Objective-C, there is little point in learning it now. Just do Swift.


And finally, this is not the appropriate method anyway. This one checks to see if the window should close or not. You don't have to call orderOut: on the sender. You definitely don't want to call makeKeyAndOrderFront: on another window or whatever object parentWindow is. For Objective-C, the syntax is always:

[<receiver> <message>];


If there are any parameters, then the method signature will include the following for each argument:

: (<type>) <argument>

A method that takes more than one argument will have that sequence interspersed in the <message>.


If you are calling a method, you don't need the parentheses.

Aug 23, 2016 5:56 AM in response to stevejobsfan0123

Etresoft mentioned most of your issues. you should also formally return either YES or NO as these are the true/false values used in Objective-C with the type BOOL.

The type bool andvalues true and false where formally added in C99 (use stdbool.h). They usually also exists in older C compilers but are then defined in some non-standard compiler/OS header.


YES and yes are usually defined as macros or enums with the value of 1 while NO and no get the value 0, so either version should work, but passing a bool value in place of a BOOL one could make the compiler complain.

Aug 23, 2016 6:38 AM in response to stevejobsfan0123

Hello


You may explore the following sample code in pyobjc as a proof of concept.


Closing window 2 will open window 1 and closing window 1 will open window 2. Closing window 3 (status window at bottom) will quit the application.


Briefly tested with pyobjc 2.2b3 and python 2.6.1 under OS X 10.6.8.



#!/usr/bin/python # coding: utf-8 # # NSWindow: close to swich window # from AppKit import * class AppDelegate(NSObject): def init(self): self = super(AppDelegate, self).init() self.win1 = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_( NSMakeRect(0, 0, 600, 300), NSTitledWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask | NSResizableWindowMask, NSBackingStoreBuffered, False) self.win1.setLevel_(NSNormalWindowLevel) self.win1.setTitle_('window 1 (close to open window 2)') self.win1.center() self.win1.setDelegate_(self) self.win2 = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_( NSMakeRect(0, 0, 500, 400), NSTitledWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask | NSResizableWindowMask, NSBackingStoreBuffered, False) self.win2.setLevel_(NSNormalWindowLevel) self.win2.setTitle_('window 2 (close to open window 1)') self.win2.center() self.win2.setDelegate_(self) self.win3 = NSWindow.alloc().initWithContentRect_styleMask_backing_defer_( NSMakeRect(0, 0, 400, 50), NSTitledWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask | NSResizableWindowMask, NSBackingStoreBuffered, False) self.win3.setLevel_(NSStatusWindowLevel) self.win3.setTitle_('status window (close to quit)') self.win3.setDelegate_(self) return self def applicationDidFinishLaunching_(self, notif): try: NSApp.activateIgnoringOtherApps_(True) self.win2.orderFront_(self) self.win3.orderFront_(self) except: NSApp.terminate_(self) raise def applicationShouldTerminate_(self, sender): return NSTerminateNow def windowShouldClose_(self, sender): if sender == self.win1: sender.orderOut_(self) self.win2.makeKeyAndOrderFront_(self) return False elif sender == self.win2: sender.orderOut_(self) self.win1.makeKeyAndOrderFront_(self) return False elif sender == self.win3: NSApp.terminate_(self) return True else: return True def main(): app = NSApplication.sharedApplication() delegate = AppDelegate.alloc().init() app.setDelegate_(delegate) app.run() main()




Good luck,

H

This thread has been closed by the system or the community team. You may vote for any posts you find helpful, or search the Community for additional answers.

Control behavior of window close button

Welcome to Apple Support Community
A forum where Apple customers help each other with their products. Get started with your Apple Account.