Creating a Color Meter Using Cocoa
Pages: 1, 2
The controller object
In object-oriented programming, there are several paradigms for organizing objects and classes in an application. Our application is simple so our needs for organization are simple.
We will employ what is known as the Model-View-Controller paradigm. "View" is the interface of your application -- the sliders, text fields, and color well in our application. "Model" is the data model for our application.
Our application doesn’t deal with data at all, so we won’t have a model object. "Controller" is an object that that links your interface to the data model. In this paradigm, the interface should not know anything about how the data is stored and managed, and the model should have no knowledge of how to display the interface. It's the controller object’s responsibility to communicate between these two realms. Let's make our controller object.
From the classes tabbed view, find the NSObject class in the list of available classes. We want to create a subclass of it. Do this by selecting "Subclass" from the Classes menu, and name it "Controller".
Now add the objects and actions shown in the picture below with the same names. New objects and actions can be created from the same Classes menu.
|
The next step is to instantiate our new class so we can connect the outlets and actions to their appropriate interface objects. The names should explain how to wire them up. Remember, wire actions by starting at the interface object -- a slider -- and control-drag to the instance of the Controller. Objects are wired in the opposite direction. Remember, wire in the direction messages would travel.
Once you have made all the connections, you need to add the interface and implementation files of our controller class to our project in Project Builder. This is done easily enough by going back to the Classes tab, selecting the Controller class, and then selecting Create Files from the Classes menu.
Close Interface Builder and return to Project Builder.
Coding
The way our color meter application operates is as follows: The user of the application will be able to slide the color sliders about for each component of the final color: red, green, blue, and alpha. As the user manipulates the controls, the color will update in real time. Additionally, the value of the slider will be displayed in the text field to the right of each slider. Now, all we have to do is supply the code that will create a color in the color well that corresponds to the values of red, green, blue, and alpha.
The first thing we want to do is declare four instance variables of type "float" that store values of each component of the final color. In the interface file Controller.h insert after the IBOutlet instance variables the following four variables:
float redValue;
float greenValue;
float blueValue;
float alphaValue;
Additionally, we want to add a method to this class that will update the color displayed in the color well. That method is
- (void)updateColor;
So our code should look like this:
#import <Cocoa/Cocoa.h>
@interface Controller : NSObject
{
IBOutlet id alphaField;
IBOutlet id alphaSlider;
IBOutlet id blueField;
IBOutlet id blueSlider;
IBOutlet id colorWell;
IBOutlet id greenField;
IBOutlet id greenSlider;
IBOutlet id redField;
IBOutlet id redSlider;
float redValue;
float greenValue;
float blueValue;
float alphaValue;
}
- (IBAction)setAlpha:(id)sender;
- (IBAction)setBlue:(id)sender;
- (IBAction)setGreen:(id)sender;
- (IBAction)setRed:(id)sender;
- (void)updateColor;
@end
The four action methods that set the color components will all have the same structure.
Here is the code for setBlue:
- (IBAction)setBlue:(id)sender
{
blueValue = [sender floatValue];
[blueField setFloatValue:blueValue];
[blueSlider setFloatValue:blueValue];
[self updateColor];
}
In the first line, we are asking the sender who is invoking the setBlue method for the floatValue of its data, and storing that in blueValue. In this case, the sender can be one of two objects in the interface.
If you recall, we wired both the Blue slider control and the Blue text field to the same action. Depending on the user's actions, either of these objects can be the sender of the message invoking this method. This is nature of all IBAction methods. That is, the action method argument is the sender object. This makes it easy to get information from the interface, while maintaining a good deal of flexibility in our code, as was demonstrated here. It also means we don’t have to write an additional action methods for additional controls to interact with. We can add as many controls as we want to change the blue color value and wire them all to this same action. This is also the power of polymorphism, as all Cocoa controls respond to the floatValue method in the same way, by returning a float-typed number.
The purpose of the middle two lines is to synchronize the values displayed in the slider and the text field. Thus, if the slider was the sender, the text field would take on the appropriate value, and vice versa. The setFloatValue: method does the exact opposite as floatValue. Where floatValue returns the value of the control as a float, setFloatValue: takes a float argument and sets the controls data value to the argument.
The last line simply tells the controller object (self, since this method is sending a message from itself to itself) to update the color displayed in the color well. We could have put the appropriate code to update the color in the color well in each of the "set...methods", but one of the goals of object-oriented programming is to reuse as much code as possible. Thus, by extracting the update code from each method and placing it in its own method, which is called by the "set...methods", we are reusing that code. The clear benefit of this is that if we want to change that code for whatever reason, we need only do it in one place, rather than four.
The setGreen:, setRed:, and setAlpha commands are exactly the same as setBlue:, except everywhere you see Blue, you replace it with Red, Green, or Alpha; and everywhere you see blue, you replace it with red, green, or alpha.
Since updateColor is not an Interface Builder action method like the others, we have to define it manually (that's why we had to add it to the interface file earlier as well). Here is the code for the updateColor: method:
- (void)updateColor
{
NSColor *aColor = [NSColor colorWithCalibratedRed:redValue green:greenValue blue:blueValue alpha:alphaValue];
[colorWell setColor:aColor];
}
What we do first is create a new color by calling the colorWithCalibratedRed: green: blue: alpha: method and store the returned color object in the aColor variable, which is declared locally on the same line. The NSColor method we invoke here is one of many that are available for creating colors. There are some NSColor class methods that return a present color, such as redColor. If you want to read more about NSColor, check out its class reference page here: NSColor (Objective-C).
Finally, in the same way we display a number in a text field using setFloatValue:, we display a color in the color well object by sending it a setColor: message with the newly created color object.
The end
And that’s it! Compile your code (hopefully, you won’t have any errors), run it, and play around with it. If you want to see another cool freebie in Cocoa, click on the color well and before your very eyes watch the system color-picker appear. Now we didn’t add any code to update the text fields and sliders to reflect the new color being set in the color well through the picker, but I encourage you to read the class references for the classes we talked about, and see if you can’t make that work (if you get stuck, write it up as a Talk Back and we'll figure it out online).
|
In the next few columns, I’m going to be doing less complete applications, and talk more about individual classes from the Foundation framework that deal with strings, numbers, and collections. Hope you enjoyed this one. Talk to you next time!
Michael Beam is a software engineer in the energy industry specializing in seismic application development on Linux with C++ and Qt. He lives in Houston, Texas with his wife and son.
Read more Programming With Cocoa columns.
Return to the Mac DevCenter.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 62 of 62.
-
I just completed my assignment...
2004-09-21 14:04:13 clsanchez [Reply | View]
Its only a year late, can I still get partial credit if I updated fields based on the colorwell selection. I also added Hue, Saturation & Brightness.
I had to review some posings to complete the extra credit and was hoping to get an explanation as to the difference in float * and float and how & plays into chaning one direction to th eother.
Thanks,
Chris
-
Nice series
2003-10-27 05:14:29 anonymous2 [Reply | View]
With Xcode coming out I decided to give this series of articles another go.
A lot of stuff I fail to understand - but I managed to put together this app with various snippets of code - some from the article - some from the reactions of other people here. I feel like 6 years old and playing with lego building blocks :)
I regret that the series does not contain a link to the source - it however makes people really try and make it work for themselves! (just look at the reactions from others!)
Tip: if it does not work - don't get frustrated. Try again, preferably from scratch. Take your time, and don't cut and copy, but type in manually and try and figure out why something does what it does (or doesn't). If you do get it working - congrats - but now the fun begins. Experiment - add code - try to make it do new stuff.
Now ... on to the next challenge :)
PS. once you get the hang of Xcode it is kick-ass! Debug and fix makes experimenting a lot of fun ... and extremely fast! I really regret nobody is adapting this series to the new environment of Xcode.
-
Can't get a decent build
2003-08-19 11:06:36 anonymous2 [Reply | View]
Controller.h:22: parse error before '{' token
Controller.h:29: parse error before '{' token
Controller.h:36: parse error before '{' token
Controller.h:43: parse error before '{' token
Controller.h:50: parse error before '{' token
Controller.m:21: warning: incomplete implementation of class `Controller'
Controller.m:21: warning: method definition for `-updateColor' not found
Basically none of the code is recognised as being valid.
I have connected the interface as suggested (both ways), the code is error-free, but it just won't compile.
Interface Builder gives me a warning stating "one of the children has a missing/uncomplete connection" because the colorwell outlet doesn't have a target. That's a bummer, since there's no action for it. Just for the heck of it, I've bound it to one of the 4 available actions, which makes the error warning disappear, but doesn't help otherwise.
I did bind colorWell to NSColorWell.
I've put my project online at http://www.verspeelt.com/colormeter.zip.
Maybe a helpful soul can tell me what the heck I've been doing wrong all this time.
I'm more thinking about install error or system screwup than error in project.
Cheers,
Koen van Hees -
Can't get a decent build
2003-08-19 11:46:15 anonymous2 [Reply | View]
I forgot to put in my email address:
that's koen"at"verspeelt.com.
excuse the stupid "at" for @ but I've been blissfully spamfree the last month (first time in years) by deleting all registered/online available email accounts ...
cheers
-
? What kind of application and whats up with the classes tab
2003-08-03 09:44:02 anonymous2 [Reply | View]
Hi there,
i don't know what kind of application to make in project builder... be more clear on that...
also when i use the classes tab it looks different and it does NOT contain the word "outlet" nor all the things such as bluelabel :(
What am i doing wrong? -
I just made it through this tutorial
2003-08-04 11:45:47 the_doug [Reply | View]
I'm using the Dec 2002 Dev Tools, which I imagine you are.
It should be a "Cocoa application", one of the choices in the "Application" menu when you're starting a new project in PB.
As far as the "classes" tab in the MainMenu.nib file, click on the magnifying glass drop-down menu and click on NSObject.
Then, in the "Classes" menu at the top of your screen, select "Subclass NSObject". You can then name your new object as you want, select it, and then press shift-command-I (the show info command)
If you set the drop-down menu in the show info command to Attributes, you'll be able to enter and inspect Outlets and Actions from there.
Finally, once you've gotten that to work, click on the "Instances" tab again and you'll see two tiny icons at the top right of the window. The top one is icon view, and the bottom is a kind of list view that you can use to inspect outlets, actions, and connections.
Hope this helps!
Doug
-
Really Annoying...
2003-07-24 15:42:29 anonymous2 [Reply | View]
This is a nice little example to start learning Cocoa with. I did everything in the example, but when I build and run the project, all I get is a blank window. As a newbie I really can't understand. I've started again a couple of times just to be sure. Same result. This is really annoying.
-
Color Wheel does not affect Color Well
2003-07-06 18:13:44 anonymous2 [Reply | View]
I am attempting to do the "extra credit" portion of this article, but I am unable to manually adjust the color *well* via the color *wheel.* The wheel pops up when I double-click the well, but this has no affect on either the well or the sliders/fields. I am using 10.2, which came out after this article was written...could that be the culprit?
-
Color Meter compiling problems
2003-07-06 11:02:48 anonymous2 [Reply | View]
This code won´t compile 15 errors can anyone help?
#import <Cocoa/Cocoa.h>
@interface Controller : NSObject
{
IBOutlet id alphaField;
IBOutlet id alphaSlider;
IBOutlet id blueField;
IBOutlet id blueSlider;
IBOutlet id colorWell;
IBOutlet id greenField;
IBOutlet id greenSlider;
IBOutlet id redField;
IBOutlet id redSlider;
float redValue;
float greenValue;
float blueValue;
float alphaValue;
}
- (IBAction)setAlpha:(id)sender;
{
alphaValue = [ sender floatValue];
[alphaField setFloatValue:alphaValue];
[alphaSlider setFloatValue:alphaValue];
[self updateColor];
}
- (IBAction)setBlue:(id)sender
{
blueValue = [sender floatValue];
[blueField setFloatValue:blueValue];
[blueSlider setFloatValue:blueValue];
[self updateColor];
}
- (IBAction)setGreen:(id)sender
{
greenValue = [sender floatValue];
[greenField setFloatValue:greenValue];
[greenSlider setFloatValue:greenValue];
[ self updateColor];
}
- (IBAction)setRed:(id)sender
{
redValue = [sender floatValue];
[redField setFloatValue:redValue];
[redSlider setFloatValue:redValue];
[ self updateColor];
}
- (void)updateColor
{
NSColor *aColor = [ NSColor colorWithCalibratedRed:redValue green:greenValue blue:blueValue alpha:alphaValue];
[colorWell setColor:aColor];
}
@end -
Color Meter compiling problems
2004-01-02 16:49:48 anonymous2 [Reply | View]
First of all, you do realize that you only "delcare" your methods in Controller.h, and no code goes in that file. The actual code goes in Controller.m (@implementation file). For example, this chunk of code for setAlpha: goes in Controller.m:
- (IBAction)setAlpha:(id)sender
{
alphaValue = [ sender floatValue];
[alphaField setFloatValue:alphaValue];
[alphaSlider setFloatValue:alphaValue];
[self updateColor];
}
Also, make sure that you do not have a semi-colon (;) after your method name in your Controller.m... for example, this is correct:
- (IBAction)setAlpha:(id)sender { ...code... }
and this is incorrect:
- (IBAction)setAlpha:(id)sender; { ...code... }. (Notice the semi-colon after 'sender'.)
It's quite easy to forget to take out the semi-colon if you copy and paste from your .h file to your .m file.
Hope that helps you.
-
Color Meter compiling problems
2003-07-06 10:59:27 anonymous2 [Reply | View]
This code won´t compile 15 errors can anyone help?
e78marcelo@hotmail.com
#import <Cocoa/Cocoa.h>
@interface Controller : NSObject
{
IBOutlet id alphaField;
IBOutlet id alphaSlider;
IBOutlet id blueField;
IBOutlet id blueSlider;
IBOutlet id colorWell;
IBOutlet id greenField;
IBOutlet id greenSlider;
IBOutlet id redField;
IBOutlet id redSlider;
float redValue;
float greenValue;
float blueValue;
float alphaValue;
}
- (IBAction)setAlpha:(id)sender;
{
alphaValue = [ sender floatValue];
[alphaField setFloatValue:alphaValue];
[alphaSlider setFloatValue:alphaValue];
[self updateColor];
}
- (IBAction)setBlue:(id)sender
{
blueValue = [sender floatValue];
[blueField setFloatValue:blueValue];
[blueSlider setFloatValue:blueValue];
[self updateColor];
}
- (IBAction)setGreen:(id)sender
{
greenValue = [sender floatValue];
[greenField setFloatValue:greenValue];
[greenSlider setFloatValue:greenValue];
[ self updateColor];
}
- (IBAction)setRed:(id)sender
{
redValue = [sender floatValue];
[redField setFloatValue:redValue];
[redSlider setFloatValue:redValue];
[ self updateColor];
}
- (void)updateColor
{
NSColor *aColor = [ NSColor colorWithCalibratedRed:redValue green:greenValue blue:blueValue alpha:alphaValue];
[colorWell setColor:aColor];
}
@end
-
Parse Error
2003-03-29 18:48:55 anonymous2 [Reply | View]
note: I am using the new edition of project builder. Also note I am just learning Objective C and programming in general at this time.
My first build revealed 5 parse errors for each of my setColor methods:
- (IBAction)setBlue:(id)sender
{
blueValue = [sender floatValue];
[blueField setFloatValue:blueValue];
[blueSlider setFLoatValue:blueValue];
[self updateColor];
}
The compiler selected the opening brace, and suggested that there was a parse error above it that prevented the application from compiling. What is a parse error, and what might be causing them? I suspect it is a typo, but that may not be the real culprit. Please help.
-
Java Version - Solution
2002-05-25 15:08:31 jsumnertx [Reply | View]
I've been doing these examples in Java rather than Objective C. Here's the Java version in case anyone else is trying to do the same.
Some notes:
1) Your controller MUST inherit from java.lang.Object, NOT NSObject or else it won't work and you won't get much information why.
2) The NSColor methods were a bit different
3) Use the actual data types of the controls for the outlets rather than "IBOutlet"
Enjoy!
/* Controller */
import com.apple.cocoa.foundation.*;
import com.apple.cocoa.application.*;
public class Controller extends java.lang.Object {
NSTextField alphaField; /* IBOutlet */
NSSlider alphaSlider; /* IBOutlet */
NSTextField blueField; /* IBOutlet */
NSSlider blueSlider; /* IBOutlet */
NSColorWell colorWell; /* IBOutlet */
NSTextField greenField; /* IBOutlet */
NSSlider greenSlider; /* IBOutlet */
NSTextField redField; /* IBOutlet */
NSSlider redSlider; /* IBOutlet */
float redValue=0;
float greenValue=0;
float blueValue=0;
float alphaValue=0;
public void setAlpha(NSControl sender) { /* IBAction */
alphaValue = sender.floatValue();
alphaField.setFloatValue(alphaValue);
alphaSlider.setFloatValue(alphaValue);
updateColor();
}
public void setBlue(NSControl sender) { /* IBAction */
blueValue = sender.floatValue();
blueField.setFloatValue(blueValue);
blueSlider.setFloatValue(blueValue);
updateColor();
}
public void setGreen(NSControl sender) { /* IBAction */
greenValue = sender.floatValue();
greenField.setFloatValue(greenValue);
greenSlider.setFloatValue(greenValue);
updateColor();
}
public void setRed(NSControl sender) { /* IBAction */
redValue = sender.floatValue();
redField.setFloatValue(redValue);
redSlider.setFloatValue(redValue);
updateColor();
}
private void updateColor(){
NSColor aColor;
aColor= NSColor.colorWithCalibratedRGB(redValue, greenValue, blueValue, alphaValue);
colorWell.setColor(aColor);
}
}
-
Extending ColorMeter
2001-12-27 02:47:04 michele [Reply | View]
I've tried to extend Color meter as suggested at the end of the article, just creating an action in InterfaceBuilder getColor and coding it as follows:
- (IBAction)getColor:(id)sender
{
// Retrieves the color sent by the color well and transformed to RGB name space
NSColor *aColor = [[sender color] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
redValue = [aColor redComponent];
[redField setFloatValue: redValue];
[redSlider setFloatValue: redValue];
greenValue = [aColor greenComponent];
[greenField setFloatValue: greenValue];
[greenSlider setFloatValue: greenValue];
blueValue = [aColor blueComponent];
[blueField setFloatValue: blueValue];
[blueSlider setFloatValue: blueValue];
alphaValue = [aColor alphaComponent];
[alphaField setFloatValue: alphaValue];
[alphaSlider setFloatValue: alphaValue];
}
It works fine except that there is no alpha channel. I've tried to use setIgnoresAlpha, but I don't understand how to call it.
Any hint?
Thank in advance,
Michèle
-
Color Meter[971] *** -[NSImageView setColor:]: selector not recognized
2001-10-07 18:25:38 jorgeherrera [Reply | View]
My app builds without errors, but when I run it I get this error message on the "run" window in ProjectBuilder:
Color Meter[971] *** -[NSImageView setColor:]: selector not recognized
I think the problem is in updateColor method...
someone knows what "selector not recognized" means?
thanks...
-
awakeFromNib
2001-09-16 13:49:15 sork [Reply | View]
The initial values are attributes stored in the slider controls so we can send these to the set methods already defined:
- (void)awakeFromNib
{
[self setRed:redSlider];
.
.
.
}
Bertil Holmberg -
awakeFromNib
2001-10-02 20:09:05 rick1138 [Reply | View]
Use this code (below) that initializes the variables,displays them in the text fields,and then sets the color well accordingly.This is a useful little app for OpenGL programmers-sice RGB values are calculated from 0 to 1 like OpenGL,you can experiment with color values without having to continually type them in and recompile a full application.
- (void)awakeFromNib
{
redValue = 1.0;
blueValue = 1.0;
greenValue = 1.0;
alphaValue = 1.0;
[redField setFloatValue:redValue];
[greenField setFloatValue:greenValue];
[blueField setFloatValue:blueValue];
[alphaField setFloatValue:alphaValue];
[self updateColor];
}
-
Problems with Color Meter
2001-07-19 14:02:22 iansloman [Reply | View]
I get the following messages when I build my code:
Controller.m(2 Warnings)
cannot find class (factory) method.
return type for 'colorWithCalibratedRED:green:blue:alpha' defaults to id
it is refering to the first line in - (void)updateColor
{
NSColor *aColour = [NSColor colorwithCalibratedRed:redValue green:greenValue blue:blueValue alpha:alphaValue];
[colourWell setColor:aColour];
}
Yes, I used a different spelling for colourWell and aColour, but I used the spelling consistently.
Thanks.
Ian -
Problems with Color Meter
2001-07-22 03:26:08 pengo98 [Reply | View]
I got exactly the same two warning messages as you did at one stage. After some debugging, I found some typo in the colorWithCalibratedRed:green:blue:alpha: method. After correction, the program built successfully and ran without a hitch.
Just my 2 cents.
-
Problems with Color Meter
2001-07-23 11:38:02 iansloman [Reply | View]
pengo98,
Thanks very much. That was it. My code now compiles, However, when it runs, I get only an empty window. Do you have any ideas on what I might have missed? Thanks, again.
Ian -
Problems with Color Meter
2001-07-23 17:31:05 pengo98 [Reply | View]
Is is possible that you have accidentally deleted all the interface elements on the window?
Open your nib file in Interface Builder and check your window. You can test the interface by choosing 'Test Interface' under the File menu.
After you have made sure everything's right (don't forget to check the connections) , save it and run the program again in project builder.
Hope this helps.
-
Thanks
2001-07-24 09:18:37 iansloman [Reply | View]
Thanks very much for the suggestion. My problem was that I had created another NIB file "Colour Meter.nib" and had put my window description there. I was able to delete the MainMenu.nib and rename the NIB file that I had created and it worked as described.
Ian
-
Nothing Works
2001-07-04 13:21:53 kjl007 [Reply | View]
It builds fine, but in the text fields next to the sliders, it doesn't have any numbers, doesn't update, nothing. also, when you move the sliders, the color well doesn't have any color or update. I think I did all the code.....
-
Unknown class `Controller'
2001-06-29 20:36:12 spfirman [Reply | View]
What am I missing?
Jun 29 23:25:05 ColorSlider[9999] Unknown class `Controller' in nib file, using `NSObject' instead.
Jun 29 23:25:05 ColorSlider[9999] Could not connect the action setRed: to target of class NSObject
Jun 29 23:25:05 ColorSlider[9999] Could not connect the action setRed: to target of class NSObject
-
Wierd build problem
2001-06-22 14:57:30 canyonrat [Reply | View]
Every time I try to build this project after I change anything I get 2 errors of the form:
illegal expression, found 'unknown' referencing both lines in updateColor()
Here is some output:
CompileC /Users/chrisg/Projects/ColorMeter/build/intermediates/ColorMeter.build/Objects/ppc/Controller.o
Controller.m:52: illegal expression, found `unknown'
Controller.m:54: illegal expression, found `unknown'
cpp-precomp: warning: errors during smart preprocessing, retrying in basic mode
Controller.m: In function `-[Controller updateColor]':
Controller.m:53: warning: cannot find class (factory) method.
Then if I click the hammer again, it builds fine.
Any clue what's going on here? -
RE:Wierd build problem
2001-06-27 15:28:24 larryvp [Reply | View]
You are getting these errors because you copied the code from the page and this caused some invisible control characters to get copied into project builder which you can't see. Try deleting what was copied on the line you get the error and manually typing the code in.
-
Color wheel...
2001-06-20 06:31:33 rainwadj [Reply | View]
As mentioned in the article, clicking on the color well brings up a color wheel (et al). Clicking around in the color wheel updates the color well, but not the sliders or the text fields. How would I do this? -
Color wheel...
2001-06-20 07:46:12 rainwadj [Reply | View]
I finally noticed that this was an extra credit assignment (Doh!). Here's what I came up with:
- (IBAction)updateControls:(id)sender
{
NSColor *theColor = [sender color];
redValue = [theColor redComponent];
[redField setFloatValue:redValue];
[redSlider setFloatValue:redValue];
greenValue = [theColor greenComponent];
[greenField setFloatValue:greenValue];
[greenSlider setFloatValue:greenValue];
blueValue = [theColor blueComponent];
[blueField setFloatValue:blueValue];
[blueSlider setFloatValue:blueValue];
alphaValue = [theColor alphaComponent];
[alphaField setFloatValue:alphaValue];
[alphaSlider setFloatValue:alphaValue];
}
Looking at the class defs for NSColor helped a lot. It seems like it would have been cleaner to use getRed:green:blue:alpha, since I wanted them all anyway, but compiling with [theColor getRed:redValue...] complained that redValue... was an incompatible type. The method wants float * for the parameters, and the someValue variables are floats. (I feel like I'm forgetting something very basic here...) -
Color wheel...
2001-06-20 08:26:02 davidmasters [Reply | View]
I tried a similar approach, and it does work.
To get the color I converted it to a named color space (to ensure I could then get the red, green, blue values), and then used getRed:green:blue:alpha to extract the individual values.
Can someone confirm if this is the right approach?
NSColor *aColor = [[sender color] colorUsingColorSpaceName:@"NSDeviceRGBColorSpace"];
[aColor getRed:&redValue green:&greenValue blue:&blueValue alpha:&alphaValue];
Remember to use & when passing these parameters - you have floats, the method is expecting float *.
After that, just set the floatValue of the sliders and text fields, and everything should work.
David -
Color wheel...
2001-06-20 10:40:23 rainwadj [Reply | View]
& - that's it. I knew I was forgetting something. My C is a little rusty. Or maybe a lot. :-)
colorUsingColorSpaceName is a good idea. This program works without it, but we're not supposed to code that way.
Thanks for the info. -
Color wheel...
2001-06-20 11:39:04 johnts [Reply | View]
I have the same thing as the first message. And it worked - almost. The sliders did not change when I clicked on the color wheel. Also, when I changed how the color wheel is shown to show "system pallette" (or something similar), when I clicked on a color, I was getting errors in the project window, saying that "blueComponent does not exist". I'll have to add the thing about converting it to the correct color space.
But like I said, my big problem is that the sliders don't move! -
Color wheel...
2001-06-20 12:50:22 davidmasters [Reply | View]
It is so cool seeing the sliders move as you pick the color from the color picker! The method I wrote was this:
- (IBAction)colorWellChanged:(id)sender
{
NSColor *aColor = [[sender color] colorUsingColorSpaceName:@"NSDeviceRGBColorSpace"];
[aColor getRed:&redValue green:&greenValue blue:&blueValue alpha:&alphaValue];
[alphaField setFloatValue:alphaValue];
[alphaSlider setFloatValue:alphaValue];
[blueField setFloatValue:blueValue];
[blueSlider setFloatValue:blueValue];
[greenField setFloatValue:greenValue];
[greenSlider setFloatValue:greenValue];
[redField setFloatValue:redValue];
[redSlider setFloatValue:redValue];
[self updateColor];
}
Make sure that in IB you control-drag from the color well to the Controller, and link the target outlet to the method - in this case colorWellChanged.
Also remember to declare the method in Controller.h:
- (IBAction)colorWellChanged:(id)sender;
(I've been doing Java/WebObjects programming - so I keep forgetting to declare things in the .h file!)
In the method it is not strictly necessary to call [self updateColor] at the end - after all you're changing the color well directly at this point.
Using colorUsingColorSpaceName helps to ensure that you get rgb and alpha values irrespective of the color space used in the individual panel of the color picker.
Hope this helps!
David
-
Color wheel...
2001-06-22 09:17:54 donarb [Reply | View]
Why all that code? You already have methods that set the sliders and text fields, so just call those:
- (IBAction)colorWellAction:(id)sender
{
NSColor *aColor = [sender color];
/* send messages to each color setting routine */
[self setRed:[NSNumber numberWithFloat:[aColor redComponent]]];
[self setBlue:[NSNumber numberWithFloat:[aColor blueComponent]]];
[self setGreen:[NSNumber numberWithFloat:[aColor greenComponent]]];
// [self setAlpha:[NSNumber numberWithFloat:[aColor alphaComponent]]];
}
Don -
Color wheel...
2001-06-20 19:54:29 johnts [Reply | View]
Ok. I figured it out. The code was fine. What I didn't do was connect the Sliders to the slider outlets (Control drag from the Controller object to each slider, and click the corresponding outlet and clicking Connect). Once I did that and rebuilt, it works! What helped me was I put
NSLog(@"redSlider %@",redSlider);
into the setRed: method. It wasn't showing anything for the value of the redSlider,
A lot to remember - connecting everything up to everything - both ways. -
Color wheel...
2001-06-20 19:39:24 johnts [Reply | View]
I just noticed too that when I change the value in one of the text boxes, the color changes, but the slider doesn't move either. -
Color wheel...
2001-06-20 19:28:20 johnts [Reply | View]
Hmm. Here's mine. It's pretty much the same thing:
- (IBAction)setAll:(id)sender
{
NSColor *theColor = [[sender color] colorUsingColorSpaceName:@"NSDeviceRGBColorSpace"];
blueValue = [theColor blueComponent];
redValue = [theColor redComponent];
greenValue = [theColor greenComponent];
alphaValue = [theColor alphaComponent];
[alphaField setFloatValue:alphaValue];
[alphaSlider setFloatValue:alphaValue];
[blueField setFloatValue:blueValue];
[blueSlider setFloatValue:blueValue];
[greenField setFloatValue:greenValue];
[greenSlider setFloatValue:greenValue];
[redField setFloatValue:redValue];
[redSlider setFloatValue:redValue];
}
But the sliders don't move.
-
init code
2001-06-19 13:59:30 rainwadj [Reply | View]
I noticed that the Color Meter app didn't do anything to the color well until I touched the sliders. So, I thought I'd be creative and add an init method to the Controller class:
- init
{
if (self = [super init]) {
redValue = [redSlider floatValue];
[redField setFloatValue:redValue];
.
.
.
[self updateColor];
}
return self;
}
I also tried setting redValue (etc.) to a constant, then calling both redField and redSlider. Neither way seems to do anything.
Any ideas?
-
re: init code
2001-06-19 14:11:51 davidmasters [Reply | View]
I thought of putting initialisation code in init first as well, but then thought it should be in awakeFromNib instead:
- (void)awakeFromNib
{
alphaValue = 1.0;
....
[alphaField setFloatValue:alphaValue];
[alphaSlider setFloatValue:alphaValue];
...
[self updateColor];
}
Don't know if it's right, but it seems to work!
David
-
Drag and Drop caused some problems
2001-06-18 19:56:09 kinger [Reply | View]
I Dragged and dropped the code samples into project builder. I was getting errors in the updateColor code until I basically deleted and re-added all whitespace in those lines of code. The project built fine after that. -
Drag and Drop caused some problems
2001-06-18 20:43:41 psheldon [Reply | View]
Once I had to be careful about distinguishing tabs from spaces, but I think cocoa compiler not like newtonscript and sloup (slurpee) in forcing such picky distinctions. Bbedit has something to "zap gremlins" (I think you speculated on gremlins), maybe project builder should and you have prescribed a new feature for apple!
Apple's fix might help others and so you have made a new connection in the community. Cool! That's what I want to do too.
;-)
-
controls not visible in color meter run
2001-06-18 19:01:38 psheldon [Reply | View]
I am a physicist and newton programmer and was happy that Mike Beam, physicist, wrote articles on programming in objective c . I hope to eventually develope supercomputer aps in cocoa to win a postdoc mentor to coauthor with.
I started this color meter in interface builder and then created source only later adding nib and source to a cocoa application in project builder . The controls don't show in the window .
I suggest that the window and its controls were born in the wrong context by making the project in this order . I am going to try it once again in a different order, but, if it doesn't work, I'm lost, so I wanted to put in the question early .
-
made controls visible
2001-06-18 20:37:43 psheldon [Reply | View]
Context was key. Had made ControlWindow.nib and the cocoa ap in project builder didn't know how to hook to it automatically like the standard (given) mainmenu.nib. Rebuilt in another folder very fast because I had learned in the first pass through the paper.
It took awhile of playing to catch on that transparency was to the two triangles, black and white "underneath". Enabled on the color well attribute meant that it was enabled for input with a double click that launched the picker. Double click is some sort of "polymorphic gesture" or interface guideline.
No response until I drag on transparency. Wish I had feel for "why" this was so.
Hope this helps and someone has a "why".
-
I'm missing something
2001-06-18 00:15:46 rdomidion [Reply | View]
Neat article, but I can't "wire" the actions. What is "the instance of the Controller"? The only nib I have, MainMenu.nib, does not have a "Controller" instance. I tried control-dragging the "File's Owner", like in the previous article, but the Info window does not show any of the classes I created.
Obviously I am missing something fundamental here, but what? -
I'm missing something
2001-06-18 07:13:05 Michael Beam |
[Reply | View]
Hello,
After creating a Controller class and endowing it with the necessary outlets and actions, you are supposed to create an instance of that class--a Controller object. To do this highlight the name of the class, "Controller" in the list of all available classes, and then select from the "Classes" menu something to the effect of "Create an Instance" (I'm not anywhere near my computer now, so i can't verify exactly that menu item). This should create an instance of the controller class in the "Instances" tabbed view. This is where you connect all the wires for the various outlets and actions.
-
Works great!
2001-06-16 12:30:53 donarb [Reply | View]
Great tutorial Mike.
It took me all of 15 minutes to get it running. I did the extra credit part - getting the color picker to update the sliders and fields. That's really cool, moving the cursor in the color picker window makes the sliders move like they're possessed! To make it work, all you need is one action connected from the color well to the controller.
Keep up the good work Mike.
Don -
Works great!
2001-06-19 22:43:24 johnts [Reply | View]
Ok. I tried the extra credit too. But it's not working just right. It's close, though. What I did was add a new Action in the Controller called setAll: Then I wired up the color well to the setAll: action. Now, I had to go into the source files and manually add the action - I'm assuming that once you "Create Files...", then add something after, there's no way to just update the files?
Now, in my setAll: method, I grabbed the color from the colorwell
NSColor *theColor = [sender color];
Then I got the colors and put them into the variables:
blueValue = [color blueComponent];
etc.
Then I updated the controls:
[blueField setFloatValue:blueValue];
[blueSlider setFloatValue:blueValue];
It compiled and when I run it and click the color well to get the color picker, the numbers in the text fields change, but the sliders don't. What am I missing?? I'm close, and I'm slowly figuring out this Cocoa thing - all this Action/Outlet stuff is confusing!
Thanks!
-
Debugging
2001-06-16 07:58:40 retro [Reply | View]
Thanks for your debugging. The change you made to:
[blueField setFloatValue:blueValue];
is correct, and as I was typing the code I was wondering about this.
However, the article was sufficiently vague about which connections should be made, which I liked, since it forced me to think a bit. I think I made all the right connections necessary, my project is working properly (thanks Mike, you rock, I looooovve your column!) If you don't want a spoiler, don't continue reading. :)
The connections to make are:
Alpha Slider to Controller - use setAlpha:
Alpha Text Field to Controller - use setAlpha:
etc for the other sliders/text fields
Controller to Alpha TextField - use alphaField
Controller to Alpha Slider - use alphaSlider
etc for the other sliders/text fields
Controller to Color Well - use colorWell
thebod, the only thing that I can think of is you might have mistyped the first line of updateColor. Its working for me :)
-
Reply to thebod's posts, and correction
2001-06-16 03:46:57 Michael Beam |
[Reply | View]
Hello-
For some reason, I couldn't reply directly to those posts, so here i am. You're correct about that line of code, and it should be fixed at the beginning of the week. Sorry for any frustration that might have caused you.
In response to thebod's other question, no there is not a C++ Cocoa API. There's a Java API, which i've not worked with,but i've read elsewhere that its not as complete as the Objective-C API. Just out of curiosity, why do you dislike Objective-C so much? Obj-C is the first Object-Oriented Programming language i learned. I like it better than Java anyway. I've never used C++, so i'd be interested to hear your opinion about how it compares to Obj-C. -
Reply to thebod's posts, and correction
2001-06-22 14:28:40 canyonrat [Reply | View]
I don't dislike ObjC at all but it would benefit from a few features. Namespaces is the big one. Function overloading would be nice. -
Reply to thebod's posts, and correction
2001-06-17 21:28:13 thebod [Reply | View]
I finally got the program to build without any problems. Turns out that when I copied and pasted the code for updateColor, some hidden characters must gotten thrown into the source file. After actually typing out the code for the function the program built without any problems.
My big problem with Objective-C is the syntax. It is so foreign to me. For example:
object.function(param1, param2);
is a lot more intuitive to me than:
[object function:param1 p2:param2];
I think you said in one of your articles that you like the fact that you have to identify the parameter with the value it is being set to in the parameter list when sending a message to an object. (i.e. parameter p2 is getting set to param2 in the example above) Your claim was this made the code more "self documenting." If a programmer names his variables properly, this language feature only adds redundancy and causes a lot of excessive typing. Not to mention making for really long lines of code that are likely to wrap around to the next line making it more difficult to read... but that's a minor issue.
The features I use most in C++ are operator overloading, and templates. I may be wrong, but neither Objective-C nor Java support this. (I think there may be an effort underway to get these features included into the Java language.)
Basically everything I know about Objective-C I have learned from reading your articles. So I am sure my ignorance is shining through. Hopefully as I become more familiar with Objective-C my opinion will change. :)
I have heard some rumblings about Apple releasing an Objective-C++ compiler. Does anybody know anything about this?
Mike, keep up the good work. I look forward to reading your articles. I only wish they were a little more frequent. :)
-
doesn't build
2001-06-15 21:40:54 thebod [Reply | View]
This example is seriously flawed. It doesn't come close to building. Apparently you can't pass sender as a parameter to setFloatValue, colorWell isn't defined as a class member, and I don't know what is wrong with the first line in updateColor, but the compiler chokes on it. -
builds... but still problems.
2001-06-15 22:14:04 thebod [Reply | View]
Ok, my mistake on not seeing I was supposed to make colorWell an outlet. It now builds but the application doesn't quite work. None of the text fields get updated as I move the sliders, but the colorWell does get updated. I can manually enter a value in the text fields and change the colorWell, but the sliders don't get repositioned.
The following line:
[blueField setFloatValue:sender];
and all the other like it, is incorrect according to the compiler. I get errors like "incompatible type for argument 1of setFloatValue". (passing in blueValue makes the compiler happy...)
I still can't figure out what is wrong with the first line in updateColor...
On an unrelated topic, is there a C++ interface to the Cocoa APIs? I really hate Objective-C. -
builds... but still problems.
2001-06-18 15:19:19 snoyes [Reply | View]
"
[blueField setFloatValue:sender];
"
try
[blueField setFloatValue:[sender floatValue]];
.
.
.
"On an unrelated topic, is there a C++ interface to the Cocoa APIs? I really hate Objective-C"
No. Not to belittle C++, but it would not be possible for C++ to talk Objective-C and Cocoa is way beyond the languages capabilities. C++ is a class based language but not really object oriented. You loose some things like templates and operator overloading and gain things like name parameters, pose-as, and categories. In all, you pick-up much much more than you loose. Many of C++ "features" are required to make up for its lack of dynamic execution.
As for the syntax... You get used to it pretty fast. I did C++ for 3-5 years before seeing Obj-C and thought it was strange for the first couple weeks. Now, I can't imagine going back. I have NEVER missed operator overloading, defaults, templates and C++'s horrid syntax.
-
Why setFloatvalue:sender?
2002-03-12 10:09:28 spiffyman [Reply | View]
I realize that you probably will never see this message, because I'm posting it some eight months after the original post, but for future record (and others who're having this problem), I don't think you're supposed to say setFloatValue:sender OR setFloatValue:[sender floatValue]] -- if you'll recall, blueValue (greenValue, etc.) is already defined, so you tell it to setFloatValue:blueValue.
I'm not an expert at C++ by any stretch of the imagination, but I'm finding that learning Objective-C is FAR easier than learning C++. I'm used to C++'s syntax, but, eh, I'll get used to Obj-C before long.








i like your articels very much. Thx for them.
I'm a very beginner in ObjC...
What i'm thinking about is, how can i transform this very uncomfortable floatnumbers in hex or percentage-description, like you would see it in most apps like these or just in the color-picker?
Normally you would display RGB-Color-Numbers like this:
255 - 255 -255 wich is the counterpart to
#ff ff ff and means the color white.
So you get values for each color between 0 and 255 or 00 and ff.
If you multiply R*G*B (256*256*256) you get 16.7mill colors, which is the colorspace a screen is able to display and only this values makes sence.
So i was very surprised to see the values the method's ask for, a float from 0 to 1.
But the space between 0 and 1 in float is infinite.
How you would transform a floatnumber with unknown digits into hex or percent?
I expected to find a class in the documentation which will do it for me, but i didn't.
Normaly i would try to make a modulo, but 0.12345n % 255 is 0.
So i tried to find a method in NSNumbers to make out of 0.12345n to 12345n. But i didn't find one.
Other way would be to transform the float into a string and remove the 0. at the beginning and transform again into an int.
...and so on.
What is the reason for the asked values of 0 to 1??
I never saw this before.