'Close' button in Storyboard won't link to IBAction in view controller.swift to dismiss a window - cocoa

Hello all you smart people! I am very new to Xcode 8 and Swift3, and am bringing a new meaning to the phrase 'killer app'. It'll kill me before it gets a chance to provide my pension!!! :-)
My OSX app is a stay resident app in the top right of the apple menu (info.plist set to Application is Agent(UIElement)= True). The main function of the app, executing an applescript, works fine. It is run from the app menu icon or key combo. I've added an 'about' window and the window appears if I select 'about' from the App menu and it closes if I click the red circle. However I can't seem to get an (interface) close button to close the window.
The 'about' window is generated from an NSMenuItem in AppDelegate.swift as in the code below. All I'm trying to do is close said window with a close button in the (viewcontroller)interface. It's that simple but no matter what I try I cannot link the close button in the Storyboard viewcontroller to an IBAction in viewcontroller.swift so as to add window!.close. The only option given is a 'represented object' binding. It's not possible to link to an IBAction in AppDelegate.swift either.
t must be something to do with the way the window is generated because if I build an app with a normal apple menu the interface buttons will link to actions in the code. If anyone can help please email me at pauljvallance#icloud.com and I can send you the Xcode 8.2.1 project and Swift3 code. Best regards, Paul
func windowAbout(sender: NSMenuItem){
let mainStoryboard = NSStoryboard.init(name: "Main", bundle: nil)
myWindowController = mainStoryboard.instantiateController(withIdentifier: "aboutWindowController") as!
NSWindowController
myWindowController.showWindow(self)
}

Xcode 8 appears to have introduced a bug that prevents you from making connections by dragging from an Interface Builder element to a view controller method when the method in question is defined in a class extension. You can however create the desired connection by dragging from your method to the relevant UI element in Interface Builder:

Related

Can't create IBAction ctrl-dragging UIButton to ViewController (Xcode Version 7.2)

In the middle of my creating the app, xcode quit allowing me to ctrl-drag UIButtons to VCs for creating IBActions. This happens on every VC (nine in all). It does allow for creating Outlets, though. (Pls see image -> no Action selection is showing)
xcode Version 7.2 (7C68) build target is ios9.
Is there a way to fix this?
Some things to try:
Make sure you are using one of the "Sent Events" to create the IBAction - not a Triggered Segue (that will do what you are describing) or other connection.
Try connecting not just via Ctr-drag, but via the right click menu or connections menu.
Try adding the code:
#IBAction func myAction()
{ }
... a clear circle should appear, which can be connected via dragging to the button in IB. This will create a Touch Up Inside event.
Finally, restart your project and try again.

How to Create a Document-Based OS X App that Launches with "Open..." Dialog

I am used to developing non-document-based applications with a single window, but now I am working on a document based application that I created using the document-based template in Xcode 5. When I run my application, it opens a new untitled document upon launch. Instead of automatically creating a new document, I would like my application to display an "Open..." dialog much like Xcode, TextEdit, and other Apple apps do. How do I go about implementing this? Is there a flag somewhere that I can set to show the dialog instead of a new document, or do I have to create an application delegate that shows the dialog upon launch? Thanks for your advice.
That would be customized behaviour.
In your application controller override applicationShouldOpenUntitledFile: to prevent opening a blank document at startup, then display the file dialog.
This is not hard but not obvious and takes a few steps to get going.
Add a window to your MainMenu.xib
Set the Visible at launch to NO in the inspector.
Now create an NSObject subclass in your project. You might include AppDelegate in the name because you will want to make it the delegate of your app.
In the interface header be sure to declare the protocol right after the word NSObject.
While there, add an IBOutlet property an NSWindow.
Back to the MainMenu.xib ...
Add an NSObject (blue cube) to your xib from the library and set its class to your new app delegate class.
Next connect your window to the property in your app delegate class and connect the window's delegate outlet to your app delegate.
Now the menu.
Locate the View menu in MainMenu and add one NSMenuItem.
Give it a title. "My fancy main window" or whatever.
Now connect it to your app delegate with both an IBOutlet (in case you want to fiddle with its enabled state or title later )
And add an IBAction for this menu item as well. Something like showMyFancyWindow:
This menu item will be persistent.
In your IBAction method call makeKeyAndOrderFront: with your app delegate's property for your window as the argument.
Extra credit
Add a BOOL property to your app delegate.
Something like showsMyFancyWindowAtLaunch
Create a constant NSString as a key above your #implementation line.
Add a checkbox button to your window.
Bind its value to your BOOL.
Add an IBAction method for the checkbox.
Inside that
[[NSUserDefaults sharedDefaults] setBool: self.showsMyFancyWindowAtLaunch forKey: theConstStringKeyYouCreated]
Then in your applicationDidFinishLaunching:
Use the corresponding bool:forKey: method of NSUserDefaults to check whether or not to call showMyFancyWindow: method at launch.
My solution, for MacOS 15 and Xcode 13, after fleshing out some of the hints above:
In your AppDelegate (or equivalent) class, turn off the creation of a New "Untitled" document using:
func applicationShouldOpenUntitledFile(_ sender: NSApplication) -> Bool
{
return false
}
Then, in add the following code to your applicationDidFinishLaunching() delegate method:
NSDocumentController.shared.openDocument(self)
Seems to work, though it's impossible to say whether it's a best solution or not.

How to make action to close NSPopover?

Hi I implemented an NSPopover in one of my apps, but the popover will not close. I'm guessing that it should close once I click something else, but its not. I know that there's a close popover action but that only works for a different button. How can I make it look to see that the popover is open and when it is open to close the popover when I press the same button?
I solved the problem!
First go ahead and click your .xib file.
Where you see the first responder box and files owner - click on the popover.
On the sidebar go to the attributes center
Change the behavior from Application-Defined to Transient and it should work!
That should make the popover disappear once someone has clicked outside the popover.
Another way to close the popover is to have a separate button.
Just add another NSButton and then link it to the popover on the sidebar and set it to Received actions -> perform close:

Why cannot I open the Preferences from each windows?

I have come across this Cocoa application (source code) that shows a main Window.
As long as this window is key it is possible to open the Preferences window from the Main menu as well as by hitting Command-, but when the main window is not key and another window from the same app is, the NSMenuItem is grayed out and the keyboard shortcut does not respond.
I've inspected the xib file associated to the Main Menu and that NSMenuItem is sending a openPreferences:(id)sender IBAction to the FirstResponder which sould be the NSApplication.
What am I missing (I am still a newbie at mac cocoa programming)? How can I fix it so that the preferences are reachable from each application window?
Probably the original author implemented - (BOOL)validateMenuItem:(NSMenuItem *)menuItem and returns NO under some circumstances.
NSMenuValidationProtocol documentation.
Update: Another quick guess: Maybe the object that handles the IBAction for the menu item is not in the responder chain anymore after you open the second window. NSMenuItems are only enabled if the action selector can be found in the responder chain.

How to open a launch NSWindow in Cocoa on a button click

I have an NSWindow that I defined in interface builder. I want to make it so that when the user clicks a button, it opens a new instance that NSWindow. Do I have to subclass NSWindow or something?
If you created the window in IB and it's in your main nib file, you cannot create a "new instance" each time you press a button. When you create an object in the nib file, an instance is actually created by IB and then archived into the nib file, so you get that instance. Assuming your window is wired to a variable named auxWindow on the same object that responds to your button click, and the action message is named buttonClick, you could do something like this to show it:
-(IBAction)buttonClick:(id)sender {
if(! [auxWindow isVisible] )
[auxWindow makeKeyAndOrderFront:sender];
}
This will cause the aux window that you defined in IB to appear on the screen and become the key window (and foremost window in the application). Please note, however, that if you intend to reuse this window, you must uncheck the box in the IB Inspector that says Release on Close, otherwise you will get an access violation the next time you click the button.
This is a simple answer to your basic question, but window programming can be quite complicated and is usually very specific (for instance, do you really want a panel for what you're doing?)... so I strongly suggest that you read the Window Programming Guide for more information on this topic, and then ask very specific questions here when you get stuck.
Put the window in its own nib file, then load the nib file each time. You should use NSWindowController for loading the nib, like NSDocument does.

Resources