I'm trying to make a configure sheet appear for a ScreenSaverView
subclass. After a long battle with Xcode, I'm finally getting the configure sheet to appear when "Screen Saver Options" is clicked in System Preferences (and my screen saver is selected), and the sheet behaves normally with one exception: the background is black, rendering text invisible (see image).
This occurs regardless of whether the sheet is an NSPanel
or NSWindow
class, and whether the panel is a Regular Panel, Utility Panel, or HUD Panel. The only thing I can seem to do is change is the alpha value of the panel, which as expected makes everything more transparent (but the text is still not visible). Interestingly, calling setOpaque
or setBackgroundColor
on the NSPanel
or NSWindow
don't seem to have any effect.
To figure out why it's showing up as black, we'd really need to see code for how you're creating the window.
I just did a quick test project and it seems to work OK here. IMO, the easiest solution for creating the window to return in the configureSheet
method is to use an NSWindowController
subclass to load a nib file in which you've configured the window ahead of time.
So in your ScreenSaverView
subclass, you'd define an interface something like the following:
@interface MDScreenSaverFinaglerView : ScreenSaverView {
MDScreenSaverOptionsWindowController *optionsWindowController;
NSInteger screenSaverViewMode;
}
@property (nonatomic, retain) MDScreenSaverOptionsWindowController
*optionsWindowController;
@property (nonatomic, assign) NSInteger screenSaverViewMode;
@end
Your implementation would then look like this for the configureSheet
method:
- (NSWindow *)configureSheet {
if (optionsWindowController == nil) {
optionsWindowController = [[MDScreenSaverOptionsWindowController alloc]
initWithScreenSaverView:self];
}
return optionsWindowController.window;
}
Basically, you check to see if the optionsWindowController
instance exists, creating it if necessary, then return its window
.
The interface for the custom NSWindowController
subclass would look like the following:
@interface MDScreenSaverOptionsWindowController : NSWindowController {
IBOutlet NSMatrix *optionsMatrix;
MDScreenSaverFinaglerView *screenSaverView; // non-retained/weak reference
}
- (id)initWithScreenSaverView:(MDScreenSaverFinaglerView *)aView;
@property (nonatomic, assign) MDScreenSaverFinaglerView *screenSaverView;
- (IBAction)ok:(id)sender;
@end
There's a screenSaverView
property which will allow communication back with the ScreenSaverView
subclass once the user has clicked the OK button.
The nib file for the MDScreenSaverOptionsWindowController
class (named "MDScreenSaverOptionsWindowController.xib") is set up like shown below:
The implementation of the MDScreenSaverOptionsWindowController
looks like the following:
@implementation MDScreenSaverOptionsWindowController
@synthesize screenSaverView;
- (id)initWithScreenSaverView:(MDScreenSaverFinaglerView *)aView {
NSParameterAssert(aView != nil);
if ((self = [super initWithWindowNibName:NSStringFromClass([self class])])) {
self.screenSaverView = aView;
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
[optionsMatrix selectCellWithTag:screenSaverView.screenSaverViewMode];
}
- (IBAction)ok:(id)sender {
NSInteger viewMode = [optionsMatrix selectedTag];
[[NSUserDefaults standardUserDefaults] setObject:[NSNumber
numberWithInteger:viewMode] forKey:MDScreenSaverViewModeKey];
screenSaverView.screenSaverViewMode = viewMode;
[NSApp endSheet:self.window];
}
@end
The end result:
Sample project: ScreenSaverFinagler.zip