Calling darker on a Color object and reassigning its value a certain number of times and then subsequently calling brighter the same number of times will not necessarily result in the or
Trang 1on which button you press The canvas will change color accordingly Here is the source code for ColorTest.java ; the result can be seen in Figure 9.12.
/*
* ColorTest
* Demonstrates the Color class
*/
import java.awt.*;
import java.awt.event.*;
public class ColorTest extends GUIFrame { Canvas palette;
Button bright, dark;
public final static int MIN = 0,
MAX = 255;
public ColorTest(int r, int g, int b) { super("Color Test");
r = r >= MIN && r <= MAX ? r : MIN;
g = g >= MIN && g <= MAX ? g : MIN;
b = r >= MIN && b <= MAX ? b : MIN;
palette = new Canvas();
palette.setBackground(new Color(r, g, b));
palette.setSize(200, 150);
add(palette, BorderLayout.CENTER);
Panel controlPanel = new Panel();
controlPanel.setLayout(new GridLayout(1, 0));
bright = new Button("Brighter");
338
J a
s o
l ut
n e
Color(int r, int g, int b) Constructs a Colorobject with the given red,
green, and blue values that range from 0-255
Color(int r, int g, int b, int a) Constructs a Colorobject with the given red,
green, blue, and alpha values, which range from 0-255
Color brighter() Returns a brighter version of this Color
Color darker() Returns a darker version of this Color
int getAlpha() Returns the alpha value of this Color
int getBlue() Returns the blue value of this Color
int getGreen() Returns the green value of this Color
int getRed() Returns the red value of this Color
Trang 2bright.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Color c = palette.getBackground().brighter();
palette.setBackground(c);
} });
controlPanel.add(bright);
dark = new Button("Darker");
dark.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Color c = palette.getBackground().darker();
palette.setBackground(c);
} });
controlPanel.add(dark);
add(controlPanel, BorderLayout.SOUTH);
pack();
setVisible(true);
} public static void main(String args[]) {
if (args.length != 3) { new ColorTest(0, 0, 0);
} else { new ColorTest(Integer.parseInt(args[0]),
Integer.parseInt(args[1]), Integer.parseInt(args[2]));
} } }
339
i n
FIGURE 9.12
TheColorTest
application demonstrates the
brighter()and
darker()
methods
Calling darker() on a Color object and reassigning its value a certain number
of times and then subsequently calling brighter() the same number of times will not necessarily result in the original color For instance, initially setting the color to Color.yellow and then calling this:
color = color.darker()
15 or so times, and then attempting to reverse it by calling:
color = color.brighter()
H I N T
Trang 3the same number of times ends up with color being white Calling darker() that many times gives you black, and subsequent calls to brighter() will give you grays, from darker to brighter, until you get white There is no trace of yellow If you need to keep track of the original color, use multiple Color objects—one to hold the original color and another to hold the changed colors so you can always get back to the original.
Color Values
The different values that make up colors are red, green, blue, and alpha values The values must range from 0 to 255 The lower the number is, the less of that color used to make up the resulting color Red, green, and blue are concepts that you already know Having a 0 red value means that there is no red in the color If red, green, and blue are all 0, this results in the color being black If they are all
255, the color will be white The alpha value, on the other hand, indicates its transparency or opacity, where 0 means the color is completely transparent and
255 indicates that the color is completely opaque Values in between indicate dif-ferent levels of translucency The ColorSliders application demonstrates this concept It is made up of three classes:
• ColorCanvas is the definition of the canvas used to paint the color.
• ColorChanger is a panel with sliders that allow for the adjustment of the color values.
• ColorSliders is the actual Frame of the application.
Here is the source code for the ColorCanvas application As you can see, all it does
is set its background color to white and override the paint(Graphics) method In
paint(Graphics) , it just draws a black oval and then sets the color to the fore-ground color and paints the whole canvas with it over the oval This is done so that you can see the level of transparency when you run the example.
/*
* ColorCanvas
* Displays its foreground color over a black oval
* so that the color's alpha value can be noticed more
* easily
*/
import java.awt.*;
public class ColorCanvas extends Canvas { public ColorCanvas() {
setBackground(Color.white);
}
340
J a
s o
l ut
n e
Trang 4public void paint(Graphics g) { g.setColor(Color.black);
g.fillOval(0, 0, getSize().width, getSize().height);
g.setColor(getForeground());
g.fillRect(0, 0, getSize().width, getSize().height);
} }
The ColorChanger class is a panel with four scroll bars that represent red, green, blue, and alpha values Its constructor takes five arguments The first argument
is the component whose foreground color the sliders will be adjusting and the four other arguments are the initial red, green, blue, and alpha values As you can see, it just lays out its sliders and labels that indicate the current values.
When any of the sliders are adjusted, the values are updated, the component’s foreground color is updated, and the component is repainted.
/*
* ColorChanger
* A Panel with scroll bars that represent red, green, blue,
* and alpha values that change the foreground color of the
* given Component
*/
import java.awt.*;
import java.awt.event.*;
public class ColorChanger extends Panel
implements AdjustmentListener { protected Scrollbar red, green, blue, alpha;
protected Label redLabel, greenLabel, blueLabel, alphaLabel;
protected int redVal, greenVal, blueVal, alphaVal;
protected Color color;
protected Component component;
public final static int MIN = 0,
MAX = 255;
public ColorChanger(Component c, int r, int g, int b, int a) { super();
redVal = r >= MIN && r <= MAX ? r : MIN;
greenVal = g >= MIN && g <= MAX ? g : MIN;
blueVal = b >= MIN && b <= MAX ? b : MIN;
alphaVal = a >= MIN && a <= MAX ? a : MIN;
color = new Color(redVal, greenVal, blueVal, alphaVal);
component = c;
component.setForeground(color);
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints constraints = new GridBagConstraints();
setLayout(gridbag);
red = new Scrollbar(Scrollbar.HORIZONTAL, redVal, 1,
MIN, MAX + 1);
341
i n
Trang 5constraints.ipadx = 200;
gridbag.setConstraints(red, constraints);
add(red);
redLabel = new Label("Red: " + redVal);
constraints.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(redLabel, constraints);
add(redLabel);
constraints.gridwidth = 1;
green = new Scrollbar(Scrollbar.HORIZONTAL, greenVal, 1,
MIN, MAX + 1);
green.addAdjustmentListener(this);
gridbag.setConstraints(green, constraints);
add(green);
greenLabel = new Label("Green: " + greenVal);
constraints.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(greenLabel, constraints);
add(greenLabel);
constraints.gridwidth = 1;
blue = new Scrollbar(Scrollbar.HORIZONTAL, blueVal, 1,
MIN, MAX + 1);
blue.addAdjustmentListener(this);
gridbag.setConstraints(blue, constraints);
add(blue);
blueLabel = new Label("Blue: " + blueVal);
constraints.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(blueLabel, constraints);
add(blueLabel);
constraints.gridwidth = 1;
alpha = new Scrollbar(Scrollbar.HORIZONTAL, alphaVal, 1,
MIN, MAX + 1);
alpha.addAdjustmentListener(this);
gridbag.setConstraints(alpha, constraints);
add(alpha);
alphaLabel = new Label("Alpha: " + alphaVal);
constraints.gridwidth = GridBagConstraints.REMAINDER;
gridbag.setConstraints(alphaLabel, constraints);
add(alphaLabel);
} public void adjustmentValueChanged(AdjustmentEvent e) { redVal = red.getValue();
greenVal = green.getValue();
blueVal = blue.getValue();
alphaVal = alpha.getValue();
redLabel.setText("Red: " + redVal);
greenLabel.setText("Green: " + greenVal);
blueLabel.setText("Blue: " + blueVal);
alphaLabel.setText("Alpha: " + alphaVal);
342
J a
s o
l ut
n e
Trang 6color = new Color(redVal, greenVal, blueVal, alphaVal);
component.setForeground(color);
component.repaint();
} }
The ColorSliders application puts it all together It lays out the ColorCanvas and the ColorChanger components and lets them do their work As you can see, it passes the ColorCanvas object, palette , to the ColorChanger class as the compo-nent that is updated by the sliders This application also optionally takes four arguments to initialize the color with red, green, blue, and alpha values No care
is taken to look for NumberFormatException occurrences The default color when
no arguments are passed is black, completely opaque Try running this applica-tion for yourself to get a better idea of how the color values affect the color they make up A sample run can be seen in Figure 9.13.
/*
* ColorSliders
* Tests a color's red, green, blue, and alpha values
* through the use of ColorCanvas and ColorChanger
*/
import java.awt.*;
public class ColorSliders extends GUIFrame { ColorCanvas palette;
ColorChanger sliders;
public ColorSliders(int r, int g, int b, int a) { super("Color Values Test");
palette = new ColorCanvas();
sliders = new ColorChanger(palette, r, g, b, a);
palette.setSize(150, 150);
add(palette, BorderLayout.CENTER);
add(sliders, BorderLayout.EAST);
pack();
setVisible(true);
} public static void main(String args[]) {
if (args.length != 4) { new ColorSliders(0, 0, 0, 255);
} else { new ColorSliders(Integer.parseInt(args[0]),
Integer.parseInt(args[1]), Integer.parseInt(args[2]), Integer.parseInt(args[3]));
} } }
343
i n
Trang 7Ugh! What’s that ugly flickering all about? When you run the ColorSliders application, you might notice some flickering while you are adjusting the color value sliders This occurs because of the way the component’s graphics are updated each time they are repainted This flickering problem is solved in Chapter 10, “Animation, Sounds, and Threads.”
Getting Back to the Memory Game
Now you know just about everything you need to know to program the Memory game It is made up of two classes, the MemoryCell class that describes one pic-ture cell of the game, and the Memory class, which uses multiple cells to create the game board and contains the main() method that drives the game.
Creating the MemoryCell Class
The MemoryCell class defines a single cell in the Memory game It is a Canvas that
is able to paint any of the shapes, the string, or the image, that makes up its sym-bol Remember that in the memory game, the goal is to match like symbols with
a minimum number of mismatches This class has nine static integer constants that represent which symbol the Memory cell is able to display They are NONE for
no symbol (blank), RECTANGLE , OVAL , ARC , TRIANGLE , SQUIGGLE , LINES , JAVA , which
is the graphical string "Java" , and IMAGE , a GIF image (lucy.gif).
This class also has protected variables that it uses to keep track of its states They are:
int symbol The symbol that this MemoryCell has It can be one
of the nine constants.
static Image image This stores the image that is used for cells with the
IMAGE symbol.
H I N T
344
J a
s o
l ut
n e
FIGURE 9.13
TheColorSliders
application demonstrates a color’s red, green, blue, and alpha values
Trang 8boolean matched This indicates whether this cell has been matched
with another cell.
boolean hidden This indicates whether this MemoryCell ’s symbol is
hidden.
boolean focused This indicates whether the user is focusing on this
cell (by clicking it).
Because these are protected variables, this class provides get and set methods that can be called to modify them from other classes that don’t have direct access
to these variables Some of the set methods also call repaint() because the graphical representation of the cell is dependant on the value, such as the hid-den variable If the cell is hidden, a question mark appears, if it is not hidden, its symbol appears instead Another useful method is the matches(MemoryCell)
method This method returns true if the symbol of the MemoryCell passed in matches the symbol of this MemoryCell object, otherwise it returns false Here is the source code for MemoryCell.java :
/*
* MemoryCell
* Defines one cell of the Memory game
*/
import java.awt.*;
public class MemoryCell extends Canvas { //symbol shape constants
public final static int NONE = -1,
RECTANGLE = 0, OVAL = 1, ARC = 2, TRIANGLE = 3, SQUIGGLE = 4, LINES = 5, JAVA = 6, IMAGE = 7;
protected int symbol;
protected static Image image;
protected boolean matched;
protected boolean hidden;
protected boolean focused;
public MemoryCell(int shape) { super();
setSymbol(shape);
matched = false;
hidden = true;
focused = false;
setBackground(Color.white);
image = Toolkit.getDefaultToolkit().getImage("lucy.gif");
345
i n
Trang 9setSize(80, 80);
} public void setSymbol(int shape) {
if (shape >= -1 && shape <= 7) symbol = shape;
else symbol = NONE;
} public int getSymbol() { return symbol;
} public boolean matches(MemoryCell otherMemoryCell) { return symbol == otherMemoryCell.symbol;
} public void setMatched(boolean m) { matched = m;
repaint();
} public boolean getMatched() { return matched;
} public void setHidden(boolean h) { hidden = h;
repaint();
} public boolean getHidden() { return hidden;
} public void setFocused(boolean f) { focused = f;
repaint();
} public boolean getFocused() { return focused;
} public void paint(Graphics g) {
if (hidden) { g.setColor(Color.darkGray);
g.fillRect(0, 0, getSize().width, getSize().height);
g.setColor(Color.lightGray);
g.setFont(new Font("Timesroman", Font.ITALIC, 36));
Point p = centerStringPoint("?", g.getFontMetrics());
g.drawString("?", p.x, p.y);
}
346
J a
s o
l ut
n e
Trang 10else switch (symbol) { case RECTANGLE:
g.fillRect(15, 15, 50, 50);
break;
case OVAL:
g.fillOval(15, 15, 50, 50);
break;
case ARC:
g.fillArc(15, 15, 50, 50, 45, 270);
break;
case TRIANGLE:
g.fillPolygon(new int[] {40, 15, 65},
new int[] {15, 65, 65}, 3);
break;
case SQUIGGLE:
g.drawPolyline(new int[] {15, 25, 35, 45, 55, 65},
new int[] {15, 65, 15, 65, 15, 65}, 6);
break;
case LINES:
g.drawLine(15, 15, 65, 15);
g.drawLine(15, 25, 65, 25);
g.drawLine(15, 35, 65, 35);
g.drawLine(15, 45, 65, 45);
g.drawLine(15, 55, 65, 55);
g.drawLine(15, 65, 65, 65);
break;
case JAVA:
g.setFont(new Font("Timesroman", Font.BOLD, 24));
Point p = centerStringPoint("Java", g.getFontMetrics());
g.drawString("Java", p.x, p.y);
break;
case IMAGE:
g.drawImage(image, 15, 15, 50, 50, this);
break;
default:
super.paint(g);
}
if (focused) {
if (matched) g.setColor(Color.green);
else g.setColor(Color.red);
g.drawRect(0, 0, getSize().width - 1, getSize().height - 1);
} } private Point centerStringPoint(String s, FontMetrics fm) { Point cp = new Point();
int w = fm.stringWidth(s);
int h = fm.getHeight() - fm.getLeading();
cp.x = (getSize().width - w) / 2;
cp.y = (getSize().height + h) / 2 - fm.getDescent();
return cp;
} }
347
i n