NSWindow crashes after close and reopen - objective-c

I have created an NSWindow
self.storeWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 100, 800, 660) styleMask:NSWindowStyleMaskResizable|NSWindowListOrderedFrontToBack|NSWindowStyleMaskClosable backing:NSBackingStoreBuffered defer:false];
[self.storeWindow setDelegate:self];
Which opens fine and closes fine. However if I call if again of even check for nil it crashes with EXC_BAD_ACCESS.
I declare it as a string property in the header
#property (strong,nonatomic) NSWindow *storeWindow;
if (self.storeWindow.contentView == nil) {
self.storeWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 100, 800, 660) styleMask:NSWindowStyleMaskResizable|NSWindowListOrderedFrontToBack|NSWindowStyleMaskClosable backing:NSBackingStoreBuffered defer:false];
[self.storeWindow setDelegate:self];
}
[self.storeWindow setBackgroundColor:[NSColor whiteColor]];
self.store = [[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 850, 640)];
[self.store loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:json[#"url"]]]];
[self.storeWindow.contentView addSubview:self.store];
[self.storeWindow makeKeyAndOrderFront:self.window];
Any ideas?

NSWindow’s releasedWhenClosed property can be set to change the default behavior, which is to release a window when it is closed (unless it is owned by a window controller). The property can be set in the Interface Editor’s Attributes Inspector, or programmatically, for example:
[myWindow setReleasedWhenClosed:NO];

Related

OSX custom keyboard field

I am creating an application using Unity3d platform, and I want to show native osx textfields for my osx build.
Is there way to show native text field?
I have tried to add textField to NSWindow, but it is not visible.
NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 100)];
[textField setStringValue:#"VALUE"];
NSApplication * shAp = [NSApplication sharedApplication];
NSWindow *window = [shAp windows][1];
if (window != NULL)
{
NSLog(#"window found, add subview");
[[window contentView] addSubview:textField];
}
My solution for this is using child window.
I create Child Window and then add TextField as subview.
All works fine, but I should resize child window when parent window is resizing.
NSTextField *textField = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 100, 50)];
NSApplication * shAp = [NSApplication sharedApplication];
NSWindow *window = [shAp windows][1];
NSWindow *overlayWindow = [[NSWindow alloc]initWithContentRect:newRect
styleMask:NSBorderlessWindowMask
backing:window.backingType
defer:NO];
[window addChildWindow:overlayWindow ordered:NSWindowAbove];
[[overlayWindow contentView] addSubview:textView];

NSAlert not working with NSTextField

I have an NSAlert with a NSView accessory view that contains two NSTextField's. I can put the cursor in the NSTextField's but I cannot type in them. Instead, it will type in the last line I was typing on in Xcode. I am using Xcode 6.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSAlert *passRequest = [[NSAlert alloc] init];
[passRequest setMessageText:#"Finder wants to restart. Type your password to allow this."];
[passRequest addButtonWithTitle:#"OK"];
[passRequest addButtonWithTitle:#"Cancel"];
[passRequest setAccessoryView:[InputView inputViewWithUsername:#"James Pickering"]];
NSImage *lockImage = [[NSImage alloc] initWithContentsOfFile:#"LOCK_YOSEMITE.png"];
[passRequest setIcon:lockImage];
[passRequest runModal];
}
I did implement the LSUIElement key, but even before that it wasn't running properly. Otherwise, it's straight out of the box cocoa app.
Here is my code for InputView:
#import "InputView.h"
#interface InputView ()
#property (strong, nonatomic) NSString *username;
#end
#implementation InputView
+ (InputView *)inputViewWithUsername:(NSString *)username {
InputView *view = [[self alloc] initWithFrame:NSRectFromCGRect(CGRectMake(0, 0, 321, 52))];
[view setUsername:username];
return view;
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
NSTextField *usernameLabel = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(0, 32, 71, 17))];
[usernameLabel setStringValue:#"Username:"];
[[usernameLabel cell] setBordered:NO];
[[usernameLabel cell] setBezeled:NO];
[usernameLabel setEditable:NO];
[usernameLabel setSelectable:NO];
[usernameLabel setBackgroundColor:[NSColor clearColor]];
[usernameLabel setFont:[NSFont systemFontOfSize:13]];
[self addSubview:usernameLabel];
NSTextField *passwordLabel = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(2, 2, 69, 17))];
[passwordLabel setStringValue:#"Password:"];
[[passwordLabel cell] setBordered:NO];
[[passwordLabel cell] setBezeled:NO];
[passwordLabel setEditable:NO];
[passwordLabel setSelectable:NO];
[passwordLabel setBackgroundColor:[NSColor clearColor]];
[passwordLabel setFont:[NSFont systemFontOfSize:13]];
[self addSubview:passwordLabel];
NSTextField *usernameInput = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(77, 30, 206, 22))];
[usernameInput setStringValue:self.username];
[usernameInput setFont:[NSFont systemFontOfSize:13]];
[self addSubview:usernameInput];
NSTextField *passwordInput = [[NSTextField alloc] initWithFrame:NSRectFromCGRect(CGRectMake(77, 0, 206, 22))];
[passwordInput setFont:[NSFont systemFontOfSize:13]];
[self addSubview:passwordInput];
}
#end
I am calling this function in int main.
This is your problem. An alert needs a full application set up and running its event loop. In order for typing to go to it, it will need to be the active application.
You should probably create a normal app from Xcode's template. Start with that. Get things working there. You can present your alert in an action method that's connected to a menu item or a button in a window or whatever. (You could also present in the -applicationDidFinishLaunching: app delegate method, I suppose.)
After you've got that working, if there's some reason you need this to work in an unusual context (e.g. command-line tool), you can work on that.
You are modifying the view hierarchy inside of your -drawRect: method. You must not do this.
First, -drawRect: may be called many times over the life of the view and you would be adding subviews every time it draws. More and more subviews, over and over.
Second, even if you were careful to only add them the first time, -drawRect: is for drawing and not for changing the view hierarchy. (There's -viewWillDraw if you need to make such changes just before drawing, but I don't think that's appropriate for this case, either.)
You can add the subviews in an override of -initWithFrame: instead.
By the way, you should probably use NSMakeRect() instead of NSRectFromCGRect(CGRectMake(...)).

Programmatically created window does not show up as correct size

This is my code in the applicationDidFinishLaunching function,
// Create window
NSWindow *window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 400, 300)
styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask)
backing:NSBackingStoreBuffered defer:NO];
//Create gl view
NSRect frame = [window contentRectForFrameRect:[window frame]];
MyOpenGLView *glView = [[MyOpenGLView alloc] initWithFrame:frame];
[window setContentView:glView];
[window makeFirstResponder:glView];
// Show up
[window makeKeyAndOrderFront:self];
The application builds and runs. But when it runs, the window seems to be full screen. In other words, I get the name of the application on the top left and nothing else on screen changes. Its like an empty window the size of my screen. Why does this happen and how can I fix it?
Additional information: initWithFrame function in MyOpenGLView class,
self = [super initWithFrame:frameRect];
[self myInit];
return self;
I'm going to guess you're using Automatic Reference Counting (ARC) and not manual reference counting. To review, here's your code:
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
NSWindow *window = [[NSWindow alloc] initWithContentRect:
NSMakeRect(0, 0, 400, 300) styleMask:(NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask)
backing:NSBackingStoreBuffered defer:NO];
//Create gl view
NSRect frame = [window contentRectForFrameRect:[window frame]];
MyOpenGLView *glView = [[MyOpenGLView alloc] initWithFrame:frame];
[window setContentView:glView];
[window makeFirstResponder:glView];
// Show up
[window makeKeyAndOrderFront:self];
}
Under ARC, the NSWindow you create here in this method only lasts as long as the method. In other words, it will be created, shown for a split second (if even at all) and then will immediately be deallocated and removed from the screen. In order to make it persist, you should define it as an instance variable. For example:
MDAppController.h:
#interface MDAppController : NSObject
#property (nonatomic, strong) NSWindow *window;
#end
MDAppController.m:
- (void)applicationDidFinishLaunching:(NSNotification *)notification {
self.window = [[NSWindow alloc] initWithContentRect:
NSMakeRect(0, 0, 400, 300)
styleMask:(NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask)
backing:NSBackingStoreBuffered defer:NO];
// or
// _window = ....
// ....
// Show up
[self.window makeKeyAndOrderFront:self];
// or
// [_window makeKeyAndOrderFront:self];
}
Here, you're setting the instance variable window to the NSWindow you create and since that ivar is defined as strong, it will persist after that method returns.

How to perform a [self.view addSubview: lbl] outside of ViewController Class scope?

How to perform a [self.view addSubview: lbl] outside of ViewController Class scope ?
or:
How do I add a label or another view in the mainview, outside of the ViewController class, in a different class?
thanks
- (void)viewDidLoad {
[super viewDidLoad];
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[lbl setText:#"hi there"];
[self.view addSubview:lbl];// <-- this works, but ...
// what is "self" referring to?
// and how can I declare and call from another class?
...
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[lbl setText:#"hi there"];
calcRomanAppDelegate *v = [[calcRomanAppDelegate new] init];
[v.viewController.view addSubview:lbl]; // this compiles, but...
// fails to shows a label on the form
...
UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
[lbl setText:#"hi there"];
calcRomanViewController *v = [[calcRomanViewController new] init];
[v.view addSubview:lbl]; // this just makes a call back to viewDidLoad... endless loop
}
Well, view is just a property of the UIViewController class. Assuming that you have your UIViewController *controller variable somewhere, you can just use
[controller.view addSubview:subview]
The reason that [v.viewController.view addSubview:lbl]; doesn't work is that v is a new instance of calcRomanAppDelegate. Every application has a shared instance of the app delegate, that can be accessed via [[NSApplication sharedApplication] delegate]. Therefore, your code would become:
calcRomanAppDelegate *v = (calcRomanAppDelegate *)[[NSApplication sharedApplication] delegate];
[v.viewController.view addSubview:lbl]; // this compiles but shows a blank form
Also In the code that you wrote, I will point out that the new method returns an initialized object, so you do not need the extra call to init in [[calcRomanAppDelegate new] init]. Instead of using the new method, I suggest using alloc, which doesn't call the initializer. Obviously that is not the issue in this particular case, but it's an important thing to know.
Not sure what you tried to accomplish.
But let's say you are in the view1 and want to create another view (view2) with your UILabel lbl added to this view2. Here are what you would do:
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(x, y, w, h)]; //x,y, w h are for your view2
[view addSubview:lbl];
[self.view addSubview:view2]; //self is your current viewcontroller - you add view2 on top of view1
On the other hand if you already have a ViewController class ViewController2.h, ViewController2.m and a ViewController2.xib defined. Here are what you would do:
ViewController2 *viewController2 = [[ViewController2 alloc] initWithNibName:#"ViewController2" bundle:nil];
[viewController2.view addSubview:lbl];
[self.view addSubview:viewController2.view]; //same as before, you need to add viewController2's view to the current view
Hope this help.

How do I create a Cocoa window programmatically?

My Cocoa app needs some small dynamically generated windows. How can I programmatically create Cocoa windows at runtime?
This is my non-working attempt so far. I see no result whatsoever.
NSRect frame = NSMakeRect(0, 0, 200, 200);
NSUInteger styleMask = NSBorderlessWindowMask;
NSRect rect = [NSWindow contentRectForFrameRect:frame styleMask:styleMask];
NSWindow * window = [[NSWindow alloc] initWithContentRect:rect styleMask:styleMask backing: NSBackingStoreRetained defer:false];
[window setBackgroundColor:[NSColor blueColor]];
[window display];
The problem is that you don't want to call display, you want to call either makeKeyAndOrderFront or orderFront depending on whether or not you want the window to become the key window. You should also probably use NSBackingStoreBuffered.
This code will create your borderless, blue window at the bottom left of the screen:
NSRect frame = NSMakeRect(0, 0, 200, 200);
NSWindow* window = [[[NSWindow alloc] initWithContentRect:frame
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO] autorelease];
[window setBackgroundColor:[NSColor blueColor]];
[window makeKeyAndOrderFront:NSApp];
//Don't forget to assign window to a strong/retaining property!
//Under ARC, not doing so will cause it to disappear immediately;
// without ARC, the window will be leaked.
You can make the sender for makeKeyAndOrderFront or orderFront whatever is appropriate for your situation.
A side note, if you want to programatically instantiate the application without a main nib, in the main.m file / you can instantiate the AppDelegate as below. Then in your apps Supporting Files / YourApp.plist Main nib base file / MainWindow.xib delete this entry. Then use Jason Coco's approach to attach the window in your AppDelegates init method.
#import "AppDelegate.h":
int main(int argc, char *argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
[NSApplication sharedApplication];
AppDelegate *appDelegate = [[AppDelegate alloc] init];
[NSApp setDelegate:appDelegate];
[NSApp run];
[pool release];
return 0;
}
Try
[window makeKeyAndOrderFront:self];
instead of
[window display];
Is that what you're aiming for?
Translating the top rated answer to modern swift (5) gives you something akin to this:
var mainWindow: NSWindow!
...
mainWindow = NSWindow(
contentRect: NSMakeRect(0, 0, 200, 200),
styleMask: [.titled, .resizable, .miniaturizable, .closable],
backing: .buffered,
defer: false)
mainWindow.backgroundColor = .blue
mainWindow.makeKeyAndOrderFront(mainWindow)
This is what I've come up with myself:
NSRect frame = NSMakeRect(100, 100, 200, 200);
NSUInteger styleMask = NSBorderlessWindowMask;
NSRect rect = [NSWindow contentRectForFrameRect:frame styleMask:styleMask];
NSWindow * window = [[NSWindow alloc] initWithContentRect:rect styleMask:styleMask backing: NSBackingStoreBuffered defer:false];
[window setBackgroundColor:[NSColor blueColor]];
[window makeKeyAndOrderFront: window];
This displays a blue window. I hope this is the optimal approach.