open new window from xib in cocoa - objective-c

My first project is a tool which changes the wallpaper according to the time of the day.
Therefore, I want to create a little window to select the wallpapers.
I have an alertView with three Buttons (kill changer/cancel/set wallpapers).
Pressing "set wallpapers" will run the method wall setter:
//method to set / copy / rename the wallpapers
- (void)wallsetter {
//copy chosen wallpaper to specified folder and rename it according to the time
printf("wallsetter starts...\n");
NSWindowController * wc=[[NSWindowController alloc] initWithWindowNibName:#"setter"];
[wc showWindow:self];
}
I also created a window called setter.xib with the Interface I like it to have which is now located in "supporting files".
By pressing "set wallpapers" that window should show up, but it does not. Can someone tell me how to do it? All I find are examples with .nib files but they have been replaced with the .xib.
if it helps here is a link to the complete code: wallchange#pastebin

Related

Maintaing a separate non-doc window in a doc-based app

In a document based Cocoa app (Apples TextEdit sample as base code) I need one separate window which must be initated at launchtime and closes when app terminates. This window should be in a separate NIB and accessible by a menu to hide and bring it to front again.
I read about NSWindows and NSWindowcontrollers but did not find a proper solution for my mixed approach of a document based app with a permanent non-doc-window
So I have two questions on that approach :
1. How to init a non-doc window at launchtime ?
2. How to connect a menu with open/close action to that window ?
I answer my question myself :
Willeke pointed me to the right direction. The TextEdit preference window is similiar to what I want, so I looked in the TextEdit sample and followed the code. And the solution to second question (make the window visible at launch) was very simple too.
In the subclass of the windowController is this method :
- (id)init {
self = [super initWithWindowNibName: #"sampleWindow"];
if (self) {
[self showWindow:self];
}
return self ;
}
All I had to do is to call showWindow:
Now the window always opens when the app launches. Easy ...

How to get an NSDocument subclass to print custom views

What needs to be hooked up for an NSDocument subclass to call its print methods when File->Print... is chosen?
How does the File->Print menu get hooked up? (Right now the selector/action is hooked up to first responder's print method. That's in a storyboard, while my NSDocument subclass has its own xib.)
I've tried implementing all of:
-(void)print:(id)sender;
-(void)printDocument:(id)sender;
-(void)printDocumentWithSettings:(NSDictionary *)printSettings showPrintPanel:(BOOL)showPrintPanel delegate:(id)delegate didPrintSelector:(SEL)didPrintSelector contextInfo:(void *)contextInfo;
-(NSPrintOperation*)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError *__autoreleasing *)outError;
But none of them are ever called when I choose Print. Where are these methods supposed to go/who calls them? (I also tried a basic app with a custom view and didn't have luck there either.)
Okay. Looks like the problem is due to a bug in Xcode: When creating a Document based app using storyboards the file menu is by default hooked to print: and printDocument: is not available.
The strange part is that my print: call is getting hijacked somewhere along the line but I can't figure out where (at the application level, not the document, because the print dialog is a window not a sheet). printDocument: works as expected, but must be defined manually in order to hook it up.
This is for a document-based app, targeting 10.10, and using storyboards.
In the storyboard with Main Menu, add a User Defined Action for printDocument: (This is where storyboard based differs, and I feel is a bug. Xib based do not require this User Defined Action.)
Hook up the selector for File -> Print to First Responder and choose printDocument: instead of print:
Don't define printDocument: in your NSDocument subclass. If you want to, then be sure to call super or perhaps one of the methods below.
From NSDocument.h
/* The action of the File menu's Print... item in a document-based application.
The default implementation of this method merely invokes
[self printDocumentWithSettings:[NSDictionary dictionary]
showPrintPanel:YES
delegate:nil
didPrintSelector:NULL
contextInfo:NULL].
*/
- (IBAction)printDocument:(id)sender;
The default implementation of printDocumentWithSettings in turn calls printOperationWithSettings, so you can use either of those methods to draw custom information prior to the print sheet appearing.
The accepted solution of setting the menu item to -printDocument: is correct, but not (technically) because of an Xcode bug. (It is very a poor default setting, though.)
The menu item is calling the -print: of the whatever is the first-responder. NSView implements -print:, so if anything has been set as first-responder you will print with NSView's -print:, not your document's -print:. If editing your document requires text editing, the control you are using to implement editing will be set to first-responder, and that control will get the -print:.
Take a look at the TextEdit sample code from Apple (https://developer.apple.com/library/mac/samplecode/TextEdit/Introduction/Intro.html)
In my non-document based app I have set a custom action for the print menu item. In that method I notified my controller about the print operation via NSNotificationCenter. Maybe that works for you too :)

Xcode: How should I organize my multi-window user-interface project?

Note: Using Objective-C, Cocoa, and Xcode.
At first, I did all my programming in the AppDelegate and had all user-interface elements such as windows in the same '.xib' (nib file). This worked great at first, but then as my application became more advanced with more "features", everything became extremely cluttered and the file too long for my liking.
I'm now trying to progress. I'm wondering how I should (properly and efficiently) go about having a multi-window project? My plan was to have a .xib file for every window, and put only necessary things in the AppDelegate. I would then have a core file for all necessary calculations and such to be used in my application and a Main Controller file to control outlets and actions from all windows in my app. However, I'm quite new to Objective-C and have been running into SO many issues and problems trying to set up Window Controllers and stuff.
Am I even on the right path? Am I doing it wrong? How should I manage a multi-window user-interface application in Xcode?
Thanks in advance.
For multiple windows, I think it's best to use an NSWindowController for each, with it's associated xib file for the window. I'm not sure what you mean by "a Main Controller file to control outlets and actions from all windows" -- each window controller will have outlets to its own window. You can't connect outlets across multiple xib files. You can have one window in the MainMenu.xib file that you get by default when you create a project, and use that to launch other windows perhaps, but it's hard to offer any more specific advice without knowing how all your windows relate to each other.
After Edit:
If you want to open another window, have a menu item's action method be something like this:
self.controller = [[WindowController alloc] initWithWindowNibName:#"WindowController"];
[self.controller showWindow:nil];
Here, I have a property called controller to keep a strong reference to the new window controller. If you don't do that, the controller will be deallocated, so if you have multiple windows, that you want to show at the same time, you'll need properties to hold on to them.

How to set up OSX screen saver configuration sheet?

I'm working on a screen saver for OSX (Mountain Lion) and I'm having trouble setting up the configuration sheet (so when the user clicks "Screen Saver Options..." within System Preferences, my options appear). There seem to be only two or three tutorials on writing OSX screen savers anywhere on the Internet, and they're all several years old so the material doesn't quite translate to OSX 10.8 and Xcode 4.
First of all, in my ScreenSaverView.m file, I have:
- (BOOL)hasConfigureSheet
{
return NO;
}
- (NSWindow*)configureSheet
{
return nil;
}
...and yet, in System Preferences, the "Screen Saver Options..." button is still clickable (nothing happens when it's clicked) rather than disabled as in the "Arabesque" screen saver.
What are the steps to having a configuration sheet appear when the button is clicked, and why is the button not currently disabled?
Edit:
I realized why the "Screen Saver Options..." button wasn't disabled. I had forgotten to include -(BOOL)hasConfigureSheet; in the ScreenSaverView.h file. My question about how to get the configuration sheet to appear, however, remains.
First things first: Be sure to include ScreenSaver.framework in your project; it provides the necessary classes ScreenSaverView and ScreenSaverDefaults.
You say you already have a file called ScreenSaverView.m. Couple that with you also saying that you have to export your -hasConfigureSheet method in order to make the "Screen Saver Options..." button disable. This leads me to wonder if you have subclassed ScreenSaverView as you should have done. (Did you subclass NSObject instead?) ScreenSaverView exports methods such as -hasConfigureSheet for you. You should be subclassing it, and overriding the appropriate methods in it.
A couple more things:
You should have included a xib file in your project that contains the UI for your configuration sheet, and you should have provided IBOutlets in your subclass' interface to reference the panel and the UI elements it contains (those for which you actually need an outlet, that is).
Finally, your -configureSheet method should fetch the configuration sheet in a manner similar to this (in this example, configSheet would be one of your IBOutlets):
if (configSheet == nil)
{
if ([NSBundle loadNibNamed:#"myConfigSheet" owner:self] == NO)
{
NSLog(#"load config sheet failed");
}
}
// then retrieve your defaults and set up your sheet; you should
// be working with ScreenSaverDefaults, a subclass of NSUserDefaults.
// then return 'configSheet'
Edit:
Apologies in advance if I'm about to tell you things you already know, but you did say you were having difficulties in configSheet, and so I'm simply covering all the bases.
In My_ScreensaverView.h, declare an outlet for your panel:
IBOutlet id configSheet;
Note that I used id instead of NSWindow * or NSPanel *, simply because I don't know what class you actually are using for the sheet. (Ideally, a NSPanel should be used for a sheet.)
In your nib file, make sure that the File's Owner is an instance of My_ScreensaverView. You can determine this by selecting the icon for this object and then using the Identity inspector to specify the class.
Make the connection between the configSheet outlet and the panel. One way of doing this is to hold down the Control key while dragging from the File's Owner object to the window or panel icon, then selecting configSheet from the pop-up that appears.
As always, good luck to you in your endeavors.

Programmatically creating new windows and accessing window objects in Cocoa

I'm having an issue with creating new windows in Cocoa.
Hypothetically speaking, let's say I have "WindowA" and has a button called "myButton".
When you click on "myButton", it runs this code in the following class file:
-(void)openFile2:(id)sender
{
myNextWindow = [[TestWindowController alloc] initWithWindowNibName:#"MainMenu"];
NSString *testString = #"foo";
[myNextWindow showWindow:self];
[myNextWindow setButtonText:testString];
}
The code in a nutshell makes a duplicate "WindowA" and shows it. As you can see, this code also runs a method called 'setButtonText', which is this:
- (void)setButtonText:(NSString *)passedText
{
[myButton setTitle:passedText];
}
The problem is that when I call this method locally, in the original window - the button text changes (e.g., [self setButtonText:testString]) it works. However, it does not work in the newly created window (e.g., [myNextWindow setButtonText:testString];)
When I debug the newly created window, step by step, the 'myButton' value it gives is 0x0. Do I have to manually assign controllers/delegates to the new window? I think the 'myButton' in the code isn't associated to the 'myButton' in the newly created window.
How would I fix this problem?
The first problem is that you are loading the MainMenu NIB/XIB repeatedly. That will do Very Bad Things -- the MainMenu should only be loaded once at application startup.
You want to break out any UI that needs to be loaded repeatedly into a separate NIB/XIB file (the same way a document based application has a MainMenu.xib and Document.xib files).
To properly do this, you need to understand the concept of "File's Owner" and how to leverage it properly. Note that there is also overlap with window controllers and understanding those, if you want to use them, will be helpful.