NSWindowController shows new window - xcode

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];

Related

How do I set the initial first responder per view in a cocoa app that switches between different views?

My Cocoa App uses one ViewController. I do not use the InterfaceBuilder On app launch a view will be created and the user can do stuff. When clicking a specific button the VC (as the view's delegate) receives a message and then replaces the view with another.
In this new view I want a specific UI element to be the first responder. So far I have not been successful.
The new view has a reference to the desired element (a subview), so the VC can pass it to the window's makeFirstResponder(:_) method.
I tried to do that in the following places:
at the end of the view's init
in the view controller's viewWillAppear()
in the VCs viewDidAppear()
in the latter two I tried:
if let myView = self.view as? MyView {
... here I try to set the UI element as firstResponder ...
}
But in any case I get the following Message:
[General] ERROR: Setting <NSTableView: 0x7f8c1f840600> as the first responder for window <NSWindow: 0x7f8c1ef0efc0>, but it is in a different window ((null))! This would eventually crash when the view is freed. The first responder will be set to nil.
So it appears that at the time I try to set the firstResponder the new view has not yet been attached to the window.
What I also tried is to override the MyView's becomeFirstResponder()method, assuming that when the view is finally presented in the window it will receive that command, but unfortunately this method does not get called.
Is there an easy way to specify an entry point for the responder chain / key view loop per view?

Prevent NSMenu from creating multiple instances of same NSWindow when clicked

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

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"];

Keep second window in front

i am new to mac development.
I have created an app which contain two window controller. second window launches on on first window button click. now i want to keep second window in front till it is not closed and first window not be able to userinteractive till second window closed
To make the second window appear in front of the first window and prevent the user from interacting with the first window add runModalForWindow:(NSWindow *) in the windowDidLoad of your second window controller. The code should look kind of like this:
- (void)windowDidLoad {
[super windowDidLoad];
//Whatever code you have put in your windowDidLoad method
[NSApp runModalForWindow:_browserWindow];
}

NSTableView, NSArrayController and reload only after key press?

I have the following situation:
There is one custom view inside of the first window that contains a NSTableView.
There is a second window which acts as a form for the current object behind the selection of the table view inside the first window.
Some more details:
I’ve implemented the setDoubleAction: behavior in the NSTableView that basically opens the second window
The table view is bound to the arrangedObjects of an (subclassed) NSArrayController
The specific interface elements in the second window (that opens on double click) are bound to the selection of the NSArrayController
I’ve subclassed the NSArrayController and modified the following functions:
At first I changed addObject: (or add:, this doesn’t really matter):
- (void)addObject:(id)object
{
[super addObject:object];
[self saveTemplatesToDisk];
}
Then I changed remove:
- (void)remove:(id)sender
{
[super remove:sender];
[self saveTemplatesToDisk];
}
The action that opens the preference sheet is just a one liner: [NSApp beginSheet:preferenceWindow modalForWindow:[_preferenceView window] modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
The code that get’s executed after the user presses the return key / OK button isn’t complicated either.
It just saves the current content of the array controller to disk and closes the second window:
- (IBAction)endPreferenceSheet:(id)sender
{
[templateArrayController saveTemplatesToDisk];
[NSApp endSheet:preferenceWindow];
[preferenceWindow orderOut:nil];
}
Finally here’s my problem / question
When I press the return key in the second window, the window closes, the data gets saved and the NSTableView gets properly reloaded without any further interaction. But when I press on the OK button with the mouse, nothing seems to happen. Here’s the interesting part: when I now select another row in the table view in the first window after the second window disappeared, the previously selected row (read: the updated object) gets properly reloaded and displays the content I’ve edited in the second window that has interface elements bound to the selection.
Basically my implementation works, but not when the user uses the mouse to close the window.
The only difference I can spot is the currentEvent, but I can’t imagine how this could change the behavior of this simple application.
When I press the OK button with the mouse: NSEvent: type=LMouseUp loc=(563.055,30.1484) time=58450.2 flags=0 win=0x0 winNum=5371 ctxt=0x0 evNum=8093 click=1 buttonNumber=0 pressure=0 subtype=NSTabletPointEventSubtype deviceID=0 x=19469 y=15838 z=0 buttons=0x0 pressure=0.000000 tilt={0.453108, -0.140629} rotation=0.000000 tangentialPressure=0.000000 vendor1-3=(0, 0, 0)
When I press return: NSEvent: type=KeyDown loc=(0,300) time=58474.8 flags=0 win=0x0 winNum=5371 ctxt=0x0 chars="
" unmodchars="
" repeat=0 keyCode=36
Any ideas how I can solve my problem?
Remember the responder chain: The keyboard event starts at the first responder, which will be the field editor, then (if that doesn't handle it) goes to the next responder, which will be the table view. The mouse event goes directly to the view that the user clicked on, which is the button.
So, the difference is that the table view handles the return event, but it never sees the mouse event. When the user clicks, you simply get an action message from the button—the table view remains in in editing mode.
The solution is to have the action method tell the controller to commit editing before proceeding with the actual action.

Resources