Get UINavigationController-like behavior in a Mac application - macos

I'm very new for mac application. Previously I've worked only for iPhone application and now I've started to learn mac application. I've created a simple application, for every application we have default toolbar at the top of the screen. So on clicking new I want to stay on the current window and switch to different view where I've a back button on clicking that I want to move back to previous view. Same as in iphone "PushviewController" and "Popviewcontroller" please suggest me any way. I've tried with following code but they are not working properly as I need.
-(IBAction)newDocument:(id)sender
{
NSLog(#"<><><>Test");
NewWindow *newWindow = [[[NewWindow alloc] initWithWindowNibName:#"NewWindow"] autorelease];
NSView *view = [[newWindow window] contentView];
NSLog(#"%#",view);
[[self window] setContentView:view];
//[[newWindow window] becomeKeyWindow];
//[NSApp beginSheet:[newWindow window] modalForWindow:[self window] modalDelegate:self didEndSelector:nil contextInfo:nil];
}
- (IBAction)goBack:(NSButton *)sender
{
[[self window] resignKeyWindow];
}

Related

Can't set position of modal window

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

Full Screen Cocoa Application - Force Quit

I am facing a weird issue when trying to make a full screen application. I am currently using a a NSWindow with a NSBorderlessWindowMask to make the screen show at top, and I subclassed NSWindow to accept keys:
- (BOOL) canBecomeKeyWindow
{
return YES;
}
This works fine, and I can use keys in my window, and quit out of the application with Command + Q. However, when I try to force quit the application on my Mac, the screen freezes, and I must restart my computer. I have a simple WebView inside my Window:
mainWindow = [[MyBorderWindow alloc] initWithContentRect:screenRect
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO screen:[NSScreen mainScreen]];
[mainWindow setLevel:windowLevel];
[mainWindow setBackgroundColor:[NSColor blackColor]];
[mainWindow makeKeyAndOrderFront:nil];
NSView *contentView = [mainWindow contentView];
WebView *customView = [[WebView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];
[contentView addSubview:customView];
I have tried the application on another computer, and force quit does not freeze the screen. Both computers are running OS X Mavericks.
Please let me know if there is anything else I should add.
Thanks in advance,
Bucco
Edit:
I think that my applicationWillTerminate method in AppDelegate might be part of the issue, but am not sure. Why would this method work fine on another computer, but not mine?
- (void)applicationWillTerminate:(NSNotification *)notification
{
[mainWindow orderOut:self];
// Release the display(s)
if (CGDisplayRelease( kCGDirectMainDisplay ) != kCGErrorSuccess) {
NSLog( #"Couldn't release the display(s)!" );
}
}

cocoa sheet on document-based app

I got a dialog instead of sheet.It worked when the app was not document-based.
Now it doesn't work.
- (IBAction) showSheet:(NSWindow*)window
{
// User has asked to see the dialog. Display it.
NSLog(#"%#", self.contragentsSheet);
if (!_contragentsSheet)
[NSBundle loadNibNamed: #"contragentsSheet" owner: self];
[NSApp beginSheet:self.contragentsSheet
modalForWindow: [[NSApp delegate]window]
//modalForWindow: window
modalDelegate: self
didEndSelector: NULL
contextInfo: NULL];
//[contragentSearch becomeFirstResponder];
//NSLog ( #"Sheet is launched");
NSLog(#"%#", [[NSApp delegate]window]);
}
Don't use [[NSApp delegate] window] you need to explicitly tell the method which window you want to display the sheet on. Document based Apps can have many windows and a sheet is attached to one.

Cocoa: NSApp beginSheet sets the application delegate?

I am trying to display a custom sheet in my application, but I think I am doing something wrong. While everything seems to be working just fine, I have a rather odd side-effect. (which took hours to figure out). It turns out that everytime I display a sheet in my application, the Application delegate gets set to the instance of the sheet, thus my Controller gets unset as the delegate causing all sorts of problems.
I've created a NIB file which I called FailureSheet.xib. I laid out my interface in IB, and then created a subclass of 'NSWindowController' called 'FailureSheet.m' which I set to the File's Owner. Here is my FailureSheet class:
#import "FailureSheet.h"
#implementation FailureSheet // extends NSWindowController
- (id)init
{
if (self = [super initWithWindowNibName:#"FailureSheet" owner:self])
{
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (IBAction)closeSheetTryAgain:(id)sender
{
[NSApp endSheet:[self window] returnCode:1];
[[self window] orderOut:nil];
}
- (IBAction)closeSheetCancel:(id)sender
{
[NSApp endSheet:[self window] returnCode:0];
[[self window] orderOut:nil];
}
- (IBAction)closeSheetCancelAll:(id)sender
{
[NSApp endSheet:[self window] returnCode:-1];
[[self window] orderOut:nil];
}
#end
Nothing complex going on here. Now this is how I display the FailureSheet in my 'Controller' class:
sheet = [[FailureSheet alloc] init];
[NSApp beginSheet:[sheet window]
modalForWindow:window
modalDelegate:self
didEndSelector:#selector(failureSheetDidEnd:etc:etc:)
contextInfo:nil];
Now if I log what the [NSApp delegate] is before displaying my sheet, it is <Controller-0x012345> which is correct. Then, after running this code and my sheet is up, if I log it again it is <FailureSheet-0xABCDEF>.
Not sure what I'm doing wrong here - Any ideas?
This is one of those "I'm-an-idiot" answers.
Turns out I at some point I accidentally made a connection in my sheet's NIB file between the Application and the File's Owner (FailureSheet) setting it as the delegate. So, everytime it got loaded it overwrote the existing delegate connection I had in my MainMenu NIB file.

Multiple custom controls that use mouseMoved in one window

At first I had one window with my custom control. To get it to accept the mouse moved events I simply put in it's awakeFromNib:
Code:
[[self window] makeFirstResponder:self];
[[self window] setAcceptsMouseMovedEvents:YES];
Now I'm doing something with four of them in the same window, and this doesn't work so pretty anymore. First off, I took them out of the control's awakeFromNib and decided I'd use my appController to manage it i.e. [window makeFirstResponder:View]
My question is, how do I manage four of these in the same view if I want each one to respond to mouse moved events? Right now, I've told the window to respond to mouseMoved events but none of the views are responding to mouseMoved.
You will also need to override -acceptsFirstResponder to return YES.
#pragma mark NSResponder Overrides
- (BOOL)acceptsFirstResponder
{
return YES;
}
-mouseMoved events are expensive so I turn off mouse moved events when my control's -mouseExited message is called and I turn it on in -mouseEntered.
- (void)mouseEntered:(NSEvent *)theEvent
{
[[self window] setAcceptsMouseMovedEvents:YES];
[[self window] makeFirstResponder:self];
}
- (void)mouseMoved:(NSEvent *)theEvent
{
...
}
- (void)mouseExited:(NSEvent *)theEvent
{
[[self window] setAcceptsMouseMovedEvents:NO];
}
I quickly tested this in my custom control application. I duplicated the control several times in the nib file and it worked as expected.
You may also need:
- (void)awakeFromNib
{
[[self window] setAcceptsMouseMovedEvents:YES];
[self addTrackingRect:[self bounds] owner:self userData:NULL assumeInside:YES];
}
I don't think the -setAcceptsMouseMovedEvents is necessary, but I'm pretty sure the tracking rect code is. You may also need to experiment with the value of the assumeInside: parameter, but that is documented.

Resources