Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
hi there... i'm currently just starting to work with bindings in my cocoa project. i'm able to change the width and height position so that when when the app restarts the main window's height and width are the way i left them... however, i can't figure out how to save the actual screen position of the window...

also... i have a custom view that just changes colors using the color picker, but the only options i have in bindings for my custom view are "Hidden" or "Tool Tip"... i'd also like to save the last color the custom view was changed to... i know this is very simple for text by binding text color, but how do i enable a saved state for my custom view with only "Hidden" or "Tool Tip" ???
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
hi there... i'm currently just starting to work with bindings in my cocoa project. i'm able to change the width and height position so that when when the app restarts the main window's height and width are the way i left them... however, i can't figure out how to save the actual screen position of the window...

Are you using NSWindow's setFrameAutosaveName: method? This saves the window's frame (which include position and size) into the standard user defaults automatically.

Darkroom said:
also... i have a custom view that just changes colors using the color picker, but the only options i have in bindings for my custom view are "Hidden" or "Tool Tip"... i'd also like to save the last color the custom view was changed to... i know this is very simple for text by binding text color, but how do i enable a saved state for my custom view with only "Hidden" or "Tool Tip" ???

You'd have to write your own custom IB palette for this, but that's just extra work unless you plan on distributing your view. Easiest way to save the view's color is to put the color value into the standard user defaults when the color changes.
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
thanks... my main window now saves it's position, width and height by writing this into the mainWindow.m:

Code:
- (void)awakeFromNib {
   [self setFrameAutosaveName:@"PositionHeightWidth"];
}


also, to save the custom view's state i couldn't find anything about setViewAutosaveName, so i'm sure that's not the proper method name...

writing this doesn't seem to work because it seems the NSView will not respond to setAutosavesName

Code:
[self setAutosavesName:@"LastImportedColor"];
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,630
Western US
also, to save the custom view's state i couldn't find anything about setViewAutosaveName, so i'm sure that's not the proper method name...

writing this doesn't seem to work because it seems the NSView will not respond to setAutosavesName

Code:
[self setAutosavesName:@"LastImportedColor"];
A view inside a window will size and position itself based on the rules you set up for it in IB, so there is no way to save that unless you want to write some custom code to resize it which breaks your rules. You resize the window and then the views within it should fall into place. If you mean to set the color of your view, as Kainjow said, write the NSColor into user defaults, then have your view read that value back out of defaults and assign it to the view's NSColor holder variable in its awakeFromNib: method.

EDIT: See this page for help in storing and retrieving an NSColor into user defaults.
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
thanks for the info... i understand most of it, except for the "[forKey:aKey];" part...

what i'm attempting to do is have the color of the NSView saved when the application quits, therefore have the save code written in the quit function (i actually have my own quit function instead of just using the built in function)... so i thinking it would resemble something like this:

Code:
- (IBAction)quitApplication:(id)sender {
	SetSystemUIMode(kUIModeNormal, 0);
	timer = [[NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(allWindowsFadeOUT:) userInfo:nil repeats:YES] retain];
}

- (void)allWindowsFadeOUT:(NSTimer *)theTimer
	{
	if (([mainWindow alphaValue] > 0.0) || ([mainWindow2 alphaValue] > 0.0)){
	[mainWindow setAlphaValue:[mainWindow alphaValue] - 0.1];
	[mainWindow2 setAlphaValue:[mainWindow2 alphaValue] - 0.1];
	[aboutWindow setAlphaValue:[aboutWindow alphaValue] - 0.1];
	[[NSColorPanel sharedColorPanel] setAlphaValue:[[NSColorPanel sharedColorPanel] alphaValue] -0.1];
	}
	else
	{
	[timer invalidate];
        [timer release];
        timer = nil;

[B]NSData *theData=[NSArchiver archivedDataWithRootObject:fillColor];
[[NSUserDefaults standardUserDefaults] setObject:theData forKey:aKey];[/B]

	[NSApp terminate:nil];
	}
}

"fillColor" is the name of the NSColor of my custom view.

next... the NSColor of my custom view of the application should start by default (or with first install and first load) as whiteColor... so i assume something like this should work:

Code:
- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {

[B]NSColor * fillColor =nil;
NSData *theData=[[NSUserDefaults standardUserDefaults] dataForKey:aKey];
if (theData != nil)
    {fillColor =(NSColor *)[NSUnarchiver unarchiveObjectWithData:theData];}
     else
     {fillColor = [NSColor whiteColor];}[/B]

    return self;
}

but alas, it's a no go... no surprise of course since i don't at all understand the aKey purpose... plus i'm sure my coding is pretty wonky...

any thoughts?
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,630
Western US
but alas, it's a no go... no surprise of course since i don't at all understand the aKey purpose... plus i'm sure my coding is pretty wonky...
aKey is just an NSString variable (the "key phrase", if you will, to retrieving the magic data), so you have to define it somewhere before using it. Since it's a constant and should never change, you might do it as a preprocessor macro (which you'll want to put in a separate file and import it into all your classes that use it if you need to access it from more than one):
Code:
#define DEFAULTS_VIEW_COLOR_KEY	@"defaultsViewColorKey"
Then, everywhere you want the key, use the constant:
Code:
[[NSUserDefaults standardUserDefaults] setObject:theData forKey:DEFAULTS_VIEW_COLOR_KEY];
Next, you need to register your application's defaults before using them, and you can set your default color here. You typically do that in your controller class, in the static class method +initialize:, something like this:
Code:
+ (void)initialize{
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	NSData *defaultViewColorData = [NSArchiver archivedDataWithRootObject:[NSColor whiteColor]];
	NSDictionary *myDefaults = [NSDictionary dictionaryWithObject:defaultViewColorData forKey:DEFAULTS_VIEW_COLOR_KEY];
	[defaults registerDefaults:myDefaults];
}
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
so lost... my lostness could be considered offensive i'm sure... ;)

i don't have a controller class, i just thru stuff together... or i have different controller classes for different controls, so i assume it would be just as fair to add the +(void)initialize function in the windowColor.m file...

to recap, my windowColor class is a custom view. furthermore, my code is burnt, as i'm sure you can see below:

Code:
windowColor.h -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

#import <Cocoa/Cocoa.h>

@interface windowColor : NSView {
	NSColor	*fillColor;
}


@end


windowColor.m -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

#import "windowColor.h"
#define DEFAULTS_VIEW_COLOR_KEY	@"defaultsViewColorKey"

@implementation windowColor

+ (void)initialize{
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	NSData *defaultViewColorData = [NSArchiver archivedDataWithRootObject:[fillColor whiteColor]];
	NSDictionary *myDefaults = [NSDictionary dictionaryWithObject:defaultViewColorData forKey:DEFAULTS_VIEW_COLOR_KEY];
	[defaults registerDefaults:myDefaults];
}

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        fillColor = [[NSUserDefaults standardUserDefaults] setObject:defaultViewColorData forKey:DEFAULTS_VIEW_COLOR_KEY];
	}
    return self;
}

- (void)dealloc {
	[super dealloc];
}

@end

it seems to me that everything is there, but i'm installing the code wrong...
 

kainjow

Moderator emeritus
Jun 15, 2000
7,958
7
What are you expecting it to do, and what is it actually doing?

You are assigning fillColor, but I don't see it being used anywhere.
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
what i'm trying to do is save my custom view's color on quit, and read the custom view's color on open (if there is no saved user default for the custom view, then it should be white)... however, what i'm actually doing is causing a trainwreck...

i've been reading this: http://developer.apple.com/document...ts.html#//apple_ref/doc/uid/20001693/BAJBFGED

but i just simply don't get it... at all...

i've tried it so many ways over the past week and nothing works for me. currently, my working code goes like this... i'm trying to include code that reads and writes to user defaults...

on application startup, there is an initWithFrame for my custom view:

Code:
- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        fillColor = [NSColor whiteColor];
	}
    return self;
}

i'm thinking that the "if (self) {fillColor = [NSColor whiteColor];" needs to have a code that will tell the custom view to read from the user default, if there is nothing there, then just appear white as usual.

secondly, i have a quit function for my app:

Code:
- (IBAction)quitApplication:(id)sender {
[NSApp terminate:nil];
}

i'm thinking that when the quit function is executing, before [NSApp terminate:nil];, there needs to be code that will write the current color of the custom view to the user defaults...

i though this was going to be one of the easiest parts to accomplish... it is so far the most difficult... who knew?
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,630
Western US
I'm attaching a sample program I wrote, maybe looking at the parts will help you figure it out.

-- When the program is launched the first time, the default preference is set to white and registered to the defaults system in the application controller's +initialize: method. After that, if the default already exists, it will do nothing, there is no need to check yourself whether it already exists. You could, if you wanted to save the steps of creating the temporary archive data and dictionary, but in this case the resources needed are negligible and probably not worth worrying about.

-- The value of the color well is bound to the user default in IB. Have a look at the Bindings tab for the color well, notice also that an option selected is to have it automatically unarchive the object data for you ("NSUnarchiveFromData"). You need to do this because you archived NSColor as raw data when you created it in the defaults system.

-- There is no need to save the default manually on exit. Because you bound the default directly to the color well, it automatically gets saved when you change it.

View attachment ColorViewTest.zip
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
thanks for the sample code hirez. i was looking into bindings a while ago, but i quickly ran into a problem because i'm not actually using a colorwell in my app... it's a straight up menu bar item "Select Color", and then the color picker pops up that is connected to the custom view... i still haven't been able to solve this problem.
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,630
Western US
thanks for the sample code hirez. i was looking into bindings a while ago, but i quickly ran into a problem because i'm not actually using a colorwell in my app... it's a straight up menu bar item "Select Color", and then the color picker pops up that is connected to the custom view... i still haven't been able to solve this problem.
OK well, if you set the color panel target to your view's changeColor: method, you can set the default manually in the action method:

Code:
- (IBAction)changeViewColor:(id)sender {
	NSData *defaultViewColorData = [NSArchiver archivedDataWithRootObject:[sender color]];
	[[NSUserDefaults standardUserDefaults] setObject:defaultViewColorData forKey:DEFAULTS_VIEW_COLOR_KEY];
	[self setViewColor:[sender color]];
	[self setNeedsDisplay:YES];
}

I'm not sure if you were the one asking before, but I made another sample app a while ago about targetting the color panel to an action (not using an NSColorWell). I'll include it here. By combining these two, you can probably make it work.

View attachment ColorPanelTest.zip
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
i'm fairly certain i tried something like this before also, but was quickly denied because apparently an NSView custom view will not respond to setViewColor (or setView or setColor)... ??

also, i'm probably getting ahead of myself here, but the reason why i originally wanted to have the color saved to the user defaults only while quitting the app is because i'm anticipating the fluid selection of the color picker will be compromised if the user defaults for the color are continuously being saved while the user is dragging the pointer over the color picker's UI... however, i did notice that the color well bindings were fine, so i could be wrong.
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,630
Western US
i'm fairly certain i tried something like this before also, but was quickly denied because apparently an NSView custom view will not respond to setViewColor (or setView or setColor)... ??
Not naturally it won't, that's why you add the changeColor: (or whatever name you want) action method and hold the current color in a variable for the view.

the reason why i originally wanted to have the color saved to the user defaults only while quitting the app is because i'm anticipating the fluid selection of the color picker will be compromised if the user defaults for the color are continuously being saved while the user is dragging the pointer over the color picker's UI... however, i did notice that the color well bindings were fine, so i could be wrong.
Yeah, it seems to perform pretty well. I'm guessing Apple saw this could be a problem and optimized the machinery for continuously-updating controls like color panels. But you could do the save on quit too. If you need to do that, I would suggest connecting your app controller object as the delegate of First Responder in IB, then catching the applicationWillTerminate: notification in your app controller implementation. This is somewhat safer than trying to make your own quit method.
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
But you could do the save on quit too. If you need to do that, I would suggest connecting your app controller object as the delegate of First Responder in IB, then catching the applicationWillTerminate: notification in your app controller implementation. This is somewhat safer than trying to make your own quit method.

i'm certainly going to stick to what's easiest... well, that's not true, but for now this problem is all my n00b brain can deal with.

so are you saying that this is defiantly possible? i've been trying to work this out for a long time now, and if it's not possible then i should probably stop and accept defeat... it seems that everyday this problem becomes more complex...

Code:
#import "TestColorView.h"
#define DEFAULTS_VIEW_COLOR_KEY	@"defaultsViewColorKey"

@implementation TestColorView

- (id)initWithFrame:(NSRect)frame {

	NSData *defaultViewColorData = [NSArchiver archivedDataWithRootObject:[NSColor whiteColor]];
	[[NSUserDefaults standardUserDefaults] dataForKey:DEFAULTS_VIEW_COLOR_KEY];
	
    self = [super initWithFrame:frame];
    if (self) {
		if (defaultViewColorData != nil) {
		fillColor = [NSUnarchiver unarchiveObjectWithData:defaultViewColorData];
        }
    }
    return self;
}

- (void)dealloc {
	[super dealloc];
}

- (IBAction)changeColor:(id)sender {
	NSData *defaultViewColorData = [NSArchiver archivedDataWithRootObject:[sender color]];
	[[NSUserDefaults standardUserDefaults] setObject:defaultViewColorData forKey:DEFAULTS_VIEW_COLOR_KEY];
	fillColor = [sender color];
	[self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)rect {
    [fillColor set];
	NSRectFill(rect);
}

@end


????
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,630
Western US
Here is a new version that doesn't use Bindings. I mostly used the code you had for the view class but made a few changes (for example, you should normally call "super" first in an init before doing anything else). I kept the defaults registration in the +initialize: method of the app controller. I strongly recommend you always create an application controller for any Cocoa app you make. Also note that I moved the import statements for the Cocoa libraries and your color defaults key into the prefix file ("ColorPanelTest_Prefix.pch"). This file will be included automatically in every file in your project, so it's a good place to put definitions and import statements you use multiple times.

View attachment ColorPanelTestNoBindings.zip
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
thanks a million for the sample code... it's kinda working now... i say kinda because there is a problem.

i receive no warning or errors in the code... if i don't change the color of the custom view, the app with quit and start fine... however, if the custom view is changed, the app freezes after i quit and restart. it locks up during startup... therefore i'm assuming it's not reading correctly the saved user default, or that there's a problem...

to make things more interesting, i actually have 2 IBActions that are connected to the custom view... one changes custom view to a color by poping up the color picker, and the other reverts the custom view back to white... for testing purposes, i've set the default value of the custom view to blue (so on first launch the view is blue) so that i can test to see if it is actually saving my revert to white or not... it's working fine for white... the app doesn't lock up when i restart if i have changed it to white, only when i have changed it to a color... below is the code of my color controller and my custom view in that order:

Code:
#import "ColorController.h"
#import "windowColor.h"
#import "HUDColorPanel.h"

@implementation ColorController

+ (void)initialize {
	[[HUDColorPanel class] poseAsClass:[NSColorPanel class]];
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	NSData *defaultViewColorData = [NSArchiver archivedDataWithRootObject:[NSColor blueColor]];
	NSDictionary *myDefaults = [NSDictionary dictionaryWithObject:defaultViewColorData forKey:DEFAULTS_VIEW_COLOR_KEY];
	[defaults registerDefaults:myDefaults];
}

- (id)init {
	if (self = [super init]) {
		[[NSColorPanel sharedColorPanel] setDelegate:self];
	}
	return self;
}

- (IBAction)selectColor:(id)sender {
	if ([[NSColorPanel sharedColorPanel] isVisible]) {
	[[NSColorPanel sharedColorPanel] makeKeyAndOrderFront:nil];}
	else {
	[[NSColorPanel sharedColorPanel] makeKeyAndOrderFront:nil];
	[[NSColorPanel sharedColorPanel] setAlphaValue:0.0];
	timer = [[NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(colorPanelFadeIN:) userInfo:nil repeats:YES] retain];
	}
}

- (void)colorPanelFadeIN:(NSTimer *)theTimer
	{
	if ([[NSColorPanel sharedColorPanel] alphaValue] < 1.0) {
	[[NSColorPanel sharedColorPanel] setAlphaValue:[[NSColorPanel sharedColorPanel] alphaValue] + 0.1];
	}
	else
	{
	[timer invalidate];
    [timer release];
    timer = nil;
	}
	[[NSColorPanel sharedColorPanel] setTarget:myColorSelection];
	[[NSColorPanel sharedColorPanel] setAction:@selector(changeColor:)];
}

- (BOOL)windowShouldClose:(id)window
	{
	timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(colorPanelFadeOUT:) userInfo:window repeats:YES];
	return NO;
}

- (void)colorPanelFadeOUT:(NSTimer *)theTimer
	{
	NSWindow* window = [timer userInfo];
	[window setAlphaValue:[window alphaValue] -0.1];
		if([window alphaValue] <= 0.0)
		{
		[timer invalidate];
		[window close];
	}
}

- (IBAction)selectWhite:(id)sender
	{
    setTarget:myWhiteSelection;
	[myWhiteSelection changeWhite:nil];
}


@end

Code:
#import "windowColor.h"

@implementation windowColor

- (id)initWithFrame:(NSRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        NSData *defaultViewColorData = [[NSUserDefaults standardUserDefaults] dataForKey:DEFAULTS_VIEW_COLOR_KEY];
		if (defaultViewColorData != nil) {
		fillColor = [NSUnarchiver unarchiveObjectWithData:defaultViewColorData];}
		}
    return self;
}

- (void)dealloc {
	[super dealloc];
	[fillColor release];
} 

- (IBAction)changeColor:(id)sender {
	NSData *defaultViewColorData = [NSArchiver archivedDataWithRootObject:[sender color]];
	[[NSUserDefaults standardUserDefaults] setObject:defaultViewColorData forKey:DEFAULTS_VIEW_COLOR_KEY];
	fillColor = [sender color];
	[self setNeedsDisplay:YES];
}

- (IBAction)changeWhite:(id)sender {
	NSData *defaultViewColorData = [NSArchiver archivedDataWithRootObject:[NSColor whiteColor]];
	[[NSUserDefaults standardUserDefaults] setObject:defaultViewColorData forKey:DEFAULTS_VIEW_COLOR_KEY];
	fillColor = [NSColor whiteColor];
	[self setNeedsDisplay:YES];
}

- (void)drawRect:(NSRect)rect {
    [fillColor set];
	NSRectFill(rect);
}


@end

any idea why it's locking up?
 

HiRez

macrumors 603
Jan 6, 2004
6,265
2,630
Western US
I can't look at all your code right now because iPhone does not allow scrolling inside those code blocks. But, I do notice you are calling [super dealloc] first in your dealloc: method. I know I said call supers first in methods, but this is really one of the few places you actually want to call it last, because otherwise you're invalidating the parent object...which means your object is probably invalid when you get to the next statement. Haha, sorry about that!

Also, you're duplicating code in that if-else statement (makeKeyAndOrderFront).

I'll try to look at it later when I get home. I suspect it is a problem with a null default or something that is causing the crash.
 

Darkroom

Guest
Original poster
Dec 15, 2006
2,445
0
Montréal, Canada
i'm not sure if this could give you more clues, but something else i've noticed is that if the app will sometimes actually start up after changing the color only if i haven't changed the size or position of the window before quitting the app... however, on a successful start up of a color custom view, i can't adjust the size of the window (well, i can one pixel at a time)... furthermore, the custom view is lost entirely if i switch from window mode to full screen mode...

also... when i delete the preferences file and load the app, the default color (blue) doesn't show up... the custom view is actually black... only a second launch, when a new preference file has been written with the default color of blue be visible... crazy...

changing to white color works perfectly still...
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.