Search code examples
swiftswift2nswindowcontrollernspanel

Use NSPanel for user input. Not opening up again


I want to display a 'NSPanel' for the user to input a name for a new folder. Why a NSPanel? Because it looks awesome! It hosts one TextField and one PushButton to confirm the name. It shall also close the window when clicked.

enter image description here

It displays when the "add" button gets clicked in my menu. It also closes when the "done" button gets clicked in the NSPanel. But when I click "add" again it doesn't show up anymore. That also occurs when I close it via the normal "close button" in the title bar. So it is not explicitly related to the "done"-PushButton. I also tested implementing func windowWillClose(notification: NSNotification) which also doesn't get triggered in either cases. What could be the problem? Also, does it somehow need to be a "new" window every time? Or am I using this correctly for user input? I mean it just gets instantiated once and then "shown" and "unshown" or am I wrong?

So I did a new Cocoa-Class - Subclass of NSWindowController - and let xCode create a .xib for that also. In that .xib I "designed" the NSPanel. I ticked visible at launch without that the window wouldn't appear when the menu button gets clicked. I also hooked up an IBOutlet for the NSPanelin my Cocoa Class. My Class at the moment looks like this:

import Cocoa

class NamingHUD: NSWindowController, NSWindowDelegate {
    @IBOutlet var insertNameWindow: NSPanel!
    @IBOutlet weak var nameTextField: NSTextField!
    override var windowNibName : String! {
        return "NamingHUD"
    }
    override func windowDidLoad() {
        super.windowDidLoad()

        insertNameWindow.center()
        insertNameWindow.makeKeyAndOrderFront(nil)
        NSApp.activateIgnoringOtherApps(true)
    }
    @IBAction func userSetName(sender: NSButton) {
        print("Close button clicked")
        insertNameWindow.close()
    }
}

In my Main Class I declared it as a variable like this:

var namingHUD:NamingHUD!

and then in override func awakeFromNib() as:

namingHUD = NamingHUD()

as well as in a click handler like:

 @IBAction func addClicked(sender: NSMenuItem) {
        namingHUD.showWindow(nil)
    }

Now. When I click and addClicked() gets called the window shows up as expected. Fine! I enter a name and hit the "done" button and it closes the window properly. Also Fine! But when I click again, say to add another folder, the window doesn't show up anymore. I also created a Preferences Window the exact same way. But with a Window instead of a NSPanel inside. That totally works as it should.

So I clearly confused something or forget something. What could it be? I openly admit that it is the first time I am working with any kind of window outside of following a tutorial. So I clearly didn't grasp the whole concept of it. I read up about windows in Apples Developer Guide and it kinda makes sense. But... well, doesn't work at the moment. Am I "misusing" the NSPanel? Shouldn't be the case as it inherits from NSWindow or?


Solution

  • Did you connect the window outlet of NamingHUD to your awesome panel? Nibs are loaded lazily:

    namingHUD = NamingHUD()   // init the controller but doesn't load the nib
    ...
    namingHUD.showWindow(nil) // now you are loading it for the first time
    

    It works the first time because showWindow() loads the nib and show the window referenced by the window outlet. Your panel shows up because it's set to "Visible at launch". Your of course had no window to show.

    Subsequent clicks don't load the nib file again, only order the window outlet to show up. That's why your panel did not show again. FYI: an NSPanel is a subclass of NSWindow so it has everything that NSWindow has, and then some more.