I have a window I want to display as a modal window (OS X 10.10). I'm loading the NIB for the window and am able to set the title successfully and then display the window. But whatever I do to try to affect the window position doesn't work.
This works (part of NSWindowController sub-class):
[[self window] setTitle:title];
[[NSApplication sharedApplication] runModalForWindow:[self window]];
Here are ways with which I've tried to affect the position after setting the title:
[[self window] setFrameOrigin: NSMakePoint(200.0, 200.0) ];
[[self window] setFrameTopLeftPoint: NSMakePoint(200.0, 200.0) ];
[[self window] setFrame: NSMakeRect(200, 300, [[self window] frame].size.width, [[self window] frame].size.height) display:YES];
(I've tried other values as well - just for testing, but nothing.)
I can even query the
[[self window] frame]
and it pretends to accept the new values, but the window stubbornly keeps showing up in the same position.
What gives?
I have solved this by
1- Make a new NSWindow subclass, overriding the center method, where you just make the frame of the new window positioned at whatever NSPoint you want:
class CenteredInParentWindow: NSWindow {
var parentMinX : CGFloat?
var parentMinY : CGFloat?
override func center() {
guard let parentMinX = parentMinX, let parentMinY = parentMinY else {
super.center()
return
}
self.setFrameOrigin(NSPoint(x: parentMinX, y: parentMinY))
}
}
2 - Set WindowController's window class to be the new NSWindow subclass, in Storyboard.
3- Instatiate the window controller and set the attributes of the subclassed window
let myWindowController = self.storyboard!.instantiateController(withIdentifier: "windowID") as! PlansWindowController
if let customWindow = myWindowController.window as? CenteredInParentWindow {
customWindow.parentMinX = NSApplication.shared.mainWindow?.frame.minX
customWindow.parentMinY = NSApplication.shared.mainWindow?.frame.minY
}
NSApp.runModal(for: myWindowController.window!)
}
You may need runModal method for making the window a modal one. Don't forget to include NSApp.stopModal() in the windowWillClose method which is available in NSWindowDelegate in your View controller
Related
Could someone let me know how can I automatically scroll the scrollView when a keyboard-only user tries to navigate between different UI Element in the ScrollView using ‘Tab’ key? When I hit "TAB" key the focus is shifted to different UI element present in the scrollView but it doesn't scroll if the UI Element is not present in the Visible Content View. How can this be achieved. Help would be appreciated. Thanks.
Solution A: Create a subclass of NSWindow and override makeFirstResponder:. makeFirstResponder is called when the first responder changes.
- (BOOL)makeFirstResponder:(NSResponder *)responder {
BOOL madeFirstResponder = [super makeFirstResponder:responder];
if (madeFirstResponder) {
id view = [self firstResponder];
// check if the new first responder is a field editor
if (view && [view isKindOfClass:[NSTextView class]] && [view isFieldEditor])
view = [view delegate]; // the control, usually a NSTextField
if (view && [view isKindOfClass:[NSControl class]] && [view enclosingScrollView]) {
NSRect rect = [view bounds];
rect = NSInsetRect(rect, -10.0, -10.0); // add a margin
[view scrollRectToVisible:rect];
}
}
return madeFirstResponder;
}
Solution B: Create a subclass of NSTextField and other controls and override becomeFirstResponder.
- (BOOL)becomeFirstResponder {
BOOL becameFirstResponder = [super becomeFirstResponder];
if (becameFirstResponder) {
if ([self enclosingScrollView]) {
NSRect rect = [self bounds];
rect = NSInsetRect(rect, -10.0, -10.0); // add a margin
[self scrollRectToVisible:rect];
}
}
return becameFirstResponder;
}
I am showing a sheet within my main window. I present the sheet using this code:
AddContactWindowController *addContact = [[AddContactWindowController alloc] initWithWindowNibName:#"AddContactWindow"];
addContact.currentViewController = myView;
self.addWindowController = addContact;
[self.view.window beginSheet: addContact.window completionHandler:^(NSModalResponse returnCode) {
NSLog(#"completionHandler called");
}];
AddContactWindowController is a NSWindowController subclass. It has a view controller within it. Inside the view is a "close" button which invokes this:
[[[self view] window] close];
This does close the window, but the completionHandler from beginSheet is not invoked. This causes me problems down the road.
Is there any particular way we should close the NSWindow sheet for the completion handler to be successfully called? I've also tried [[[self view] window] orderOut:self] but that doesn't work either.
Thanks.
You will want to call -endSheet:returnCode: on your window, rather than just ordering it out.
You must properly finish the modal session.
I used to call - (void)performClose:(id)sender and stop the modal session in the delegate method.
- (void)windowWillClose:(NSNotification *)notification {
[NSApp stopModal];
}
But for a sheet, endSheet looks more appropriate.
self.addWindowController = addContact;
[self.view.window beginSheet:self.addWindowController.window];
...
...
[self.view.window endSheet:self.addWindowController.window];
self.addWindowController = nil
I'm with a NSMenu in an agent application (without the icon in the dock). When a button from this menu is tapped, I want to show a generic NSWindowController.
My menu button action:
- (IBAction)menuButtonTapped:(id)sender {
MyWindowController *myWindow = [[MyWindowController alloc] initWithWindowNibName:#"MyWindowController"];
[myWindow showWindow:nil];
[[myWindow window] makeMainWindow];
}
But the window just "flashes" in the screen (it shows and disappears really fast).
Any solution?
The reason the window is showing up for a split second and then disappearing has to do with ARC and how you go about creating the instance of the window controller:
- (IBAction)menuButtonTapped:(id)sender {
MyWindowController *myWindow = [[MyWindowController alloc]
initWithWindowNibName:#"MyWindowController"];
[myWindow showWindow:nil];
[[myWindow window] makeMainWindow];
}
Under ARC, the myWindow instance will be valid for the scope where it is defined. In other words, after the last [[myWindow window] makeMainWindow]; line is reached and run, the window controller will be released and deallocated, and as a result, its window will be removed from the screen.
Generally speaking, for items or objects you create that you want to "stick around", you should define them as an instance variable with a strong property.
For example, your .h would look something like this:
#class MyWindowController;
#interface MDAppController : NSObject
#property (nonatomic, strong) MyWindowController *windowController;
#end
And the revised menuButtonTapped: method would look something like this:
- (IBAction)menuButtonTapped:(id)sender {
if (self.windowController == nil) {
self.windowController = [[MyWindowController alloc]
initWithWindowNibName:#"MyWindowController"];
}
[self.windowController showWindow:nil];
}
Use this:
[[myWindow window] makeKeyAndOrderFront:self];
I know how to do this in iOS but cannot figure it how to it in Cocoa.
I want to capture keyboard events and I think I need to override the acceptsFirstResponder method to accomplish that (keyDown method being triggered). So I created a class extending NSCustomView and tried to add it in the main Window but I just cannot understand how to do it. So far I added a Custom View to the main View then tried to add it programmatically like:
TestView *view = [[TestView alloc] init];
[[_window contentView] addSubview:view];
but this is not working. So how can I do this?
To see if the view has been added to a window, you can override the view's viewDidMoveToWindow method and log the value of [self window] to check (if it's nil then the view has been removed from a window):
- (void)viewDidMoveToWindow
{
NSLog(#"window=%p", [self window]);
[super viewDidMoveToWindow];
}
You should be subclassing NSView, not NSCustomView, and initWithFrame is the designated initializer for NSView, not init.
Try:
TestView *view = [[TestView alloc] initWithFrame:NSMakeRect(0, 0, 100, 200)];
[[_window contentView] addSubview:view];
I'd like to add a close button to an NSWindow programmatically. I can get the button to display, but there are no mouse-over or mouse-down effects. My "selector" never seems to get called when i click the button. I'm not really sure whats wrong and why this is so annoying.
Here is what I've been messing with:
closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask];
NSView *themeFrame = [[self contentView] superview];
NSRect c = [themeFrame frame]; // c for "container"
NSRect aV = [closeButton frame]; // aV for "accessory view"
NSRect newFrame = NSMakeRect( c.size.width - aV.size.width - 5, // x position c.size.height - aV.size.height - 5, // y position aV.size.width, // width aV.size.height); // height
[closeButton setFrame:newFrame];
[themeFrame addSubview:closeButton];
[closeButton setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[closeButton setEnabled:YES];
[closeButton setTarget:self];
[closeButton setAction:NSSelectorFromString(#"testClick:") ];
Where "testClick" is just a memeber function of my class and is defined as such:
- (void)testClick:(id)sender
The problem seems to be the call to:
[themeFrame addSubview:closeButton];
where the themeFrame is: [[self contentView] superview] Just adding the button to [self contentView] works, but I'd like it added to the titlebar.
No Interface Builder please...
Potential issue # 1)
The way you're calling "NSSelectorFromString" seems incorrect to me. I don't think you can pass parameters via this way in Objective C.
Try this:
[closeButton setAction: #selector(closeWindow:)];
and create a new "closeWindow:" action that looks like:
- (void) closeWindow: (id) sender;
which closes the window.
Potential issue # 2)
Instead of:
closeButton = [NSWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask];
NSView *themeFrame = [[self contentView] superview];
Why not use:
NSWindow * parentWindow = [[self contentView] window];
if(parentWindow)
{
closeButton = [parentWindow standardWindowButton:NSWindowCloseButton forStyleMask:self.styleMask];
}