Prevent NSMenu from creating multiple instances of same NSWindow when clicked - macos

I have a simple Cocoa Application that launches a NSWindow when an NSMenu item is clicked. I am initiating the window via a segue. The problem is when I click the menu item multiple times it keeps creating new windows instead of bringing the existing window to the foreground. How can I prevent this behavior? Thanks in advance.

Select destination window controller
Click attribute inspector and select under Presentation "Single" instead of "Multiple"

If you have your Window without using Storyboard, lets say you created separate .xib and ViewController to this .xib, you could use the following approach:
Add to your class:
lazy var testViewcontroller = TestViewController(nibName: "TestWindow", bundle: nil)
lazy var testWindow = NSWindow(contentViewController: testViewcontroller)
Then, add this to the method where you invoke the window:
testWindow.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true) // will help your window to open on top of others

Related

NSWindowController/NSViewController "Presentation" setting in Storyboard

What exactly does the Presentation option(in Attribute Inspector) do in StoryBoard for Cocoa.
It gives two options to select from
Single
Multiple
P.S When googled the title, results are related to powerpoint presentation
The presentation style affects "Show" segues. Possibly it affects other segues too, but I only tested a Show segue. I tested on OS X 10.10.5 (Yosemite) with Xcode 7.1.1.
If a window controller's presentation style is "Multiple" (the default), then a Show segue to the window controller always loads a new instance of the window controller from the storyboard. This means that you can end up with multiple instances of the window controller at once, each with its own window on the screen. By default those windows will stack on top of each other, so it won't be obvious what happened until you move or close one.
If a window controller's presentation style is "Single", and an instance of the window controller has already been loaded from the storyboard, and that window controller still exists (presumably because its window is still on screen), then a Show segue to that view controller will not create a new instance. Instead, the Show segue will bring the existing window controller's window to the front.
This behavior is useful if you want behavior like, say, Xcode's Devices window, where there can only be one such window. You create a "Devices" menu item in the Window menu in your storyboard, and connect it to the Devices window controller in the storyboard with a Show segue. Set the Devices window controller's presentation style to Single. Now the menu item will never create a second Devices window controller if one already exists.
You'll probably want to somehow set the window's excludedFromWindowsMenu property to true, so it doesn't appear twice in the Window menu (because by default it appends itself to that menu). You could, for example, use a subclass of NSWindowController that sets it:
class DevicesWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
window?.excludedFromWindowsMenu = true
}
}
View controllers also have a presentation style, because you can also connect Show segues to view controllers. A Show segue connected to a view controller automatically creates a window controller to contain the view controller at runtime. The window controller's presentation style is effectively set to the view controller's, so you get the same singleton behavior if you set the view controller's presentation to Single.
As far as I can tell, the storyboard setting has no corresponding public property or method you can use in code.
If you connect the Show segue to a storyboard reference (new in Xcode 7), then the segue ignores the presentation style of the destination window controller, and acts as if it were "Multiple". This happens even if the destination is actually in the same storyboard as the reference.

Creating an outlet for a NSProgressIndicator inside a NSToolbar

I have this OSX storyboard-based application that starts with a NSSplitViewController like this:
This splitViewController has two viewControllers: master and detail.
Inside the window I have a NSToolbar. I dragged a NSProgressIndicator to that toolbar and Xcode embedded it inside a NSToolbarItem.
Now I need to create an outlet (not an action as explained on other stackoverflow questions) from the NSProgressIndicator to some class. First question is which one?
Xcode will not let I create an outlet. I have tried these options:
dragged from the ToolbarItem to masterController class file, detailController class file and to NSSplitViewController class.
dragged from the ToolbarItem to the delegate class.
dragged from the NSProgressIndicator to masterController class file, detailController class file and to NSSplitViewController class.
dragged from the NSProgressIndicator to the delegate class.
dragged from both the NSToolbarItem and from the NSProgressIndicator to the Window Controller First Responder.
In all cases dragging does not make a window appear to allow me to create the outlet.
For heavens sake, how do I create an outlet like that? To which class I drag it and how do I do that?
I'll assume your setup is more like this image:
Your Window scene is backed, by default, by an NSWindowController, to which you cannot add new outlets. You need to create a subclass of that, associate it with your Window and then you should be able to create outlets in that.
File > New File > Cocoa Class
Specify a name like "SpaceDogsWindowController", as a subclass of NSWindowController.
Then use select the window controller icon (blue circle) and select the Identity Inspector in Xcode. (CMD+ALT+3). Specify the name of your new class in the "Class" field.
Then try to hookup an outlet:
1) Show the Assistant Editor
2) Use the Jump Bar to ensure your custom class is visible (It's at the top of the assistant editor pane, it should say Automatic and you can tap that to then select your new class; If it says 'Manual', change it to Automatic).
3) If your are control-dragging and it's still not offering to make a connection, try dragging from the document outline (also shown in the screen shot).
You could then edit that progress indicator from other view controllers, which are descendants of that window's view hierarchy, using code like this:
if let windowController = self.view.window?.windowController() as? CustomWindowController {
windowController.progressIndicator.doubleValue = 0.4
}
or, in Objective-C, something like this:
CustomWindowController *myWindowControllerSubclass = self.view.window.windowController;
windowController.progressIndicator.doubleValue = 0.4;
Hope that helps.

OS X second window won't stay open

I want to open a second window to act as a content editor for some of the fields in the main window of my app. I created a custom NSWindowController (called ItemEditor) with its own nib.
I open the new window with this code:
ItemEditor *editor = [[ItemEditor alloc] initWithWindowNibName:#"ItemEditor"];
[editor showWindow:nil];
[editor.window makeKeyAndOrderFront:nil];
The new window appears for an instant and then immediately disappears. Both the initWithWindow: and windowDidLoad of ItemEditor are called, but windowWillClose: isn't.
Can anyone tell me what's going on here? I'm stumped.
What's happening is that you're using ARC... and nothing is holding onto your "editor" object after it's created. That's why it's disappearing as soon as it's being created.
You need to make "editor" a "strong" property in your parent window controller.
In other words, declare it like this in the parent view controller's .h file:
#property (strong) ItemEditor *editor;
And replace the first line of your code snippet above with this:
self.editor = [[ItemEditor alloc] initWithWindowNibName:#"ItemEditor"];

NSWindowController shows new window

I am very new to mac programming. Just started before 3 days.
I am making a sample app in which i have one button in main window
I am using this code to open a new wndowcontroller
ThirdViewController *tvc = [[ThirdViewController alloc] initWithWindowNibName:#"SecondViewController"];
[tvc showWindow:self];
This working fine but when i press button again it will open same window again so after every click i have +1 window on screen.
What i want is if my new window is already on my screen then button can't add same window.
Thanks in advance:)
If that code is being executed whenever the button is clicked then you’re effectively creating a new window controller, loading its window from a nib file, and showing that window as many times as the button is clicked.
The standard approach to prevent this from happening is having an instance variable that is initially nil and assigning it a window controller only once. Subsequently, the instance variable is not nil any longer and you can test that to avoid creating another controller and loading the nib file again.
You could, for example, declare the following instance variable in your application delegate or whatever controller should be responsible for the third window controller:
ThirdViewController *tvc;
and, when the button is clicked:
if (nil == tvc) {
// If tvc is nil then it's the first time this code is being executed
tvc = [[ThirdViewController alloc] initWithWindowNibName:#"SecondViewController"];
}
[tvc showWindow:self];

Finding File Owner in Xcode 4.2

Please glance at the image below and help me find a File Owner for the class.
Generally i would connect my UILabel to it, but, alas, i can't find it.
Question: What should i connect my Label to?
Storyboard:
Meanwhile class is set up as
As storyboards don't have an owner, you can use the View Controller instead.
Ctrl click (or right click) the label, drag the blue line to connect up with the orange View Controller.
Right click the Label and connect to the View controller scene
You have put your finger on a key difference between storyboards and nibs: when a nib is loaded, an owner instance is specified, but a storyboard is not loaded with an owner, so there is no file's owner in a storyboard. Your ViewController instance is created by the storyboard and is proxied in the scene (listed as View Controller), so you can draw a connection between that and an interface item. But if you want to form a connection with an already-existing instance not represented in the storyboard, you'll have to identify that instance in some other way (perhaps by a tag) and find it and runtime and form the connection in code after the storyboard loads.
For example, in this code, I manually load a storyboard (to use its initial scene in a popover) and then form connections from some bar button items within it:
UINavigationController* nav =
(UINavigationController*)[[UIStoryboard storyboardWithName:#"Storyboard"
bundle:nil]
instantiateInitialViewController];
// there is no file's owner...
// so we can't just draw the connection from button items to ourself,
// because we are not proxied in the storyboard
// so, locate the button items in some other way and do it in code
UIViewController* root = [nav.viewControllers objectAtIndex: 0];
[root.navigationItem.leftBarButtonItem setTarget:self];
[root.navigationItem.leftBarButtonItem setAction:#selector(save:)];
[root.navigationItem.rightBarButtonItem setTarget:self];
[root.navigationItem.rightBarButtonItem setAction:#selector(cancel:)];
In some cases, there's a trick you can use to inject an arbitrary existing instance into a scene so that a connection to it will work: make that instance the first responder. There is a first responder proxy in every scene, so this can give you something to connect to by drawing within the storyboard. So, this code could work instead of the above:
[self becomeFirstResponder];
UINavigationController* nav =
(UINavigationController*)[[UIStoryboard storyboardWithName:#"Storyboard"
bundle:nil]
instantiateInitialViewController];
(And the button action connections have been drawn in the scene from each button to the first responder proxy object.)
Menu: Navigate - Reveal in Project Navigator
In the Project Navigator, Click on the "Main Storyboard"
Menu: View - Show Assistant Editor
You should have the Storyboard on the left with your label, and the view controler.h text on the right.
Click on your label, hold down the control button, and drag a blue line to the View Controler.h source code on the right. Type in a reference name (for example myLabel), and click connect.
Automagically you will see something like this generated:
#property (weak,nonatomic) IBOutlet UILabel *myLabel;
Inside the View Controler.m, you will see something like this generated:
#synthesize *myLabel;
Inside your IBAction events, you can set the label:
myLabel.text =

Resources