loading a borderless window from a xib with view - cocoa

I am trying to load a borderless window from a .xib in my program. I can load a borderless window with by overriding [[[NSWindow]] initWithContentRect:styleMask:backing:defer:] as follows:
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag {
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:flag];
if (!self) {
return nil;
}
[self setOpaque:NO];
[self setHasShadow:YES];
[self setLevel:NSFloatingWindowLevel];
[self setBackgroundColor:[NSColor clearColor]];
[self setAlphaValue:1.0];
// Ignore events
[self setIgnoresMouseEvents:YES];
return self;
}
When another method which contains [self orderFront:self]; is called, a window shows. However, I have a separate .xib file with a window created that I want to show when this method is called. I have the file's owner set as NSApplication and the window itself is of the class that contains the aforementioned code. How do I, when I call the method with [self orderFront:self];, load the window in the xib and show it instead of this class creating a window?

If I understand what you're trying to do, you can use NSWindowController to load an NSWindow from a separate nib (or xib) file. Sub-class NSWindowController, and put your controller code in there. Create that object in the xib file and set that to be the file's owner. Link the NSWindow to the NSWindowController's delegate outlet.
Then it's as easy as:
NSWindowController * windowController = [[[YourWindowClass alloc] initWithWindowNibName:#"YourWindowClass"] autorelease];
NSWindow * sheet = [windowController window];

Related

InitWithCoder never called for Cocoa NSView based class

I create a XIB.
I create this class called MyCustomView and assign it to the XIB's File Owner.
- (instancetype)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self) [self load];
return self;
}
- (instancetype)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) [self load];
return self;
}
- (void)load {
NSArray* topLevelObjects;
[[NSBundle mainBundle] loadNibNamed:#"MyCustomView"
owner:self
topLevelObjects:&topLevelObjects];
NSView* view;
for (id aView in topLevelObjects) {
if ([umaVista isKindOfClass:[NSView class]]) {
view = umaVista;
break;
}
}
[self addSubview:view];
view.frame = self.bounds;
}
I create a NSView on the main app.
I change that view to the MyCustomView.
I run the app. MyCustomView's initWithCoder does not run. initWithFrame does not run. awakeFromNib does not run.
Nothing happens.
Any ideas?
"File's Owner" as I've written elsewhere, isn't a real object in the archive. It's a placeholder. When you unpack the nib, a pre-existing object gets used.
It looks like you should just be putting an instance of your custom view into the nib. Don't make it File's Owner, just drag a view out from the object palette and then change its class in the Identity Inspector (right pane, top; press ⌘-⌥-3). Build the subviews in the nib too.
Then get your NSBundle to load the nib for you. Your custom view will get initWithCoder: and awakeFromNib, and you won't have to grovel through the hierarchy to find a particular subview.

How to add custom NSView to Window

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

Access main window from a NSDocument class

I have a NSDocument class, where I'd need to access the main menu window, the one that gets opened when the app start. When I operate in that window from the app all seems to work, but when trying to do the same operations from readFromFileWrapper:ofType:error: the window I access seems to be nil. Why this happens?
EDIT: Some code which deals with this:
- (BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError **)outError
{
if([[NSFileManager alloc] fileExistsAtPath:[NSString stringWithFormat:#"%#/Project.plist",[[self fileURL] path]]]) {
NSLog(#"%#", [[self fileURL] path]);
NSDictionary *project = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:#"%#/Project.plist",[[self fileURL] path]]];
if([[project objectForKey:#"type"] isEqualToString:#"vote"]) {
[self openProject:[[self fileURL] path] type:#"vote"];
return YES;
} else if([[project objectForKey:#"type"] isEqualToString:#"quiz"]) {
[self openProject:[[self fileURL] path] type:#"quiz"];
return YES;
} else {
return NO;
}
} else {
return NO;
}
}
That is my readFromFileWrapper:ofType:error: method. Here is my openProject:type: method:
-(void)openProject:(NSString *)filepath type:(NSString *)type
{
NSLog(#"Opening project # %#",filepath);
NSLog(#"%#", [MainWindow description]);
[projectDesignerView setFrame:[[[[MainWindow contentView] subviews] objectAtIndex:0] frame]];
[projectDesignerToolbar setFrame:[MainWindow frame] display:FALSE];
[[MainWindow contentView] replaceSubview:[[[MainWindow contentView] subviews]objectAtIndex:0] with:projectDesignerView];
[[projectDesignerToolbar toolbar] setShowsBaselineSeparator:YES];
[MainWindow setToolbar:[projectDesignerToolbar toolbar]];
[MainWindow setRepresentedFilename:filepath];
[MainWindow setTitle:[NSString stringWithFormat:#"%# - %#", [[filepath lastPathComponent] stringByDeletingPathExtension], [projectDesignerToolbar title]]];
NSString *path = [[NSBundle mainBundle] pathForResource:#"projectDesigner" ofType:#"html"];
NSURL *url = [NSURL fileURLWithPath:path];
[[projectDesignerWebview mainFrame] loadRequest:[NSURLRequest requestWithURL:url]];
}
NSLog(#"%#", [MainWindow description]); returns nil, when MainWindow should be the Main App Window. I think the problem is that double-clicking on a file reallocs all, and hence is failing.
It's not entirely clear what you're asking. You mention that MainWindow is an outlet in MainMenu.xib but you don't specify what class is defining the outlet.
If this window is designed to have a single main "project" window then you should assign the outlet property in your application delegate.
You can then access this from other classes using something like [(YourAppDelegate*)[NSApp delegate] mainWindow];.
If, however, you are trying to obtain a reference to the window of the current document then it's a little bit more complicated.
The reason that NSDocument does not have a window outlet by default is that it is designed to work with instances of NSWindowController that themselves manage the various windows related to the document. This is so a document can have multiple windows showing different views of the same data, additional palettes related to the document and so on. Each instance of NSWindowController would have its own window nib file and window outlet.
By default, NSDocument creates a single instance of NSWindowController for you if you do not specifically create and assign NSWindowController instances to the document. This is automatic, you don't need to even know the window controller exists.
That means that if you aren't managing your document windows with NSWindowController instances yourself, you can get the window attached to the NSWindowController that is automatically-created by NSDocument like so:
/* Only implement this in an NSDocument instance where the
automatic window controller is being used.
If the document has multiple window controllers, you must
keep track of the main window controller yourself
and return its window
*/
- (NSWindow*)documentWindow
{
if([[self windowControllers] count] == 1)
{
return [[[self windowControllers] firstObject] window];
}
return nil;
}
The normal way to handle this is to add an IBOutlet to your NSDocument subclass, then hook it up to the document window in the .xib file.
In your .h:
#interface MyDocument : NSDocument
#property (nonatomic, assign) IBOutlet NSWindow *docWindow;
#end
In your .m:
#implementation MyDocument : NSDocument
#synthesize docWindow;
#end
Then, the most important part, open up MyDocument.xib (or whatever it's called), and drag a connection from File's Owner (assuming that's your NSDocument subclass, which it is by default) to the main document window, and hook it up to the docWindow outlet.

How show sheet loaded from xib? (MacOSx)

I have a xib file with only an NSPanel in it, I'm trying to show this panel as modal sheet (with beginSheet:modalForWindow:modalDelegate:didEndSelector:contextInfo:). The file's owner for this xib is a controller class "MyController" which has the IBOutlet to the NSPanel.
What I am looking for is something like:
...
MyController *controller = [[MyController alloc] init];
[NSApp beginSheet:controller.panel modalForWindow:[NSApp mainWindow] modalDelegate:controller didEndSelector:nil contextInfo:nil];
...
Question:
Must MyController inherit from NSWindowController or NSObject?. I tried NSWindowController and initWithWindowNibName: but the outlet to NSPanel always is nil.
Thanks
I resolve it. You must deactivate almost all the properties of the window object (in the IB) that you are using for the sheet. I add the following method to my controller to show the sheet:
- (void)showInWindow:(NSWindow *)mainWindow {
if (!panelSheet)
[NSBundle loadNibNamed:#"XibName" owner:self];
[NSApp beginSheet:panelSheet modalForWindow:mainWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
[NSApp runModalForWindow:panelSheet]; //This call blocks the execution until [NSApp stopModal] is called
[NSApp endSheet:panelSheet];
[panelSheet orderOut:self];
}
panelSheet is an IBOutlet to the sheet window.
Thanks Jon Hess and JWWalker for your help

makeKeyAndOrderFront only does the latter

I am trying to open one window from another using makeKeyAndOrderFront. The new window appears, but does not receive focus.
The code for the main window is:
#import "SecondWindowController.h"
#implementation FirstWindowController
-(IBAction)showSecondWindow:(id)sender
{
if (!secondWindowController)
secondWindowController = [[SecondWindowController alloc] init];
[[secondWindowController window] makeKeyAndOrderFront:self];
}
SecondWindowController is a NSWindowController, as follows:
#implementation SecondWindowController
-(id)init
{
if (![super initWithWindowNibName:#"SecondWindow"])
return nil;
return self;
}
I've also tried putting [secondWindowController showWindow:self] before the makeKeyAndOrderFront but it doesn't make a difference.
Did you make sure the window outlet for SecondWindowController is hooked up to the window in your NIB? The window could be displayed just by loading the NIB, even if the outlet is not hooked up.
Are you using a borderless window? If so you need to override canBecomeKeyWindow and return YES
Try this:
if (!secondWindowController)
secondWindowController = [[SecondWindowController alloc] init];
NSApplication *thisApp = [NSApplication sharedApplication];
[thisApp activateIgnoringOtherApps:YES];
[[secondWindowController window] makeKeyAndOrderFront:self];

Resources