My version isn't any shorter, but hopefully, it's clearer and provides a firmer foundation to build more complex games.
When developing a Swing game, it helps to separate the model, view, and controller. This is called the model / view / controller pattern.
So, I created a model class, GameModel
. Here's the code for the GameModel
class.
public class GameModel {
private Color randomColor;
private Color userColor;
private final Random random;
public GameModel() {
this.random = new Random();
}
public void createColors() {
setRandomColor();
setUserColor();
}
public Color getUserColor() {
return userColor;
}
public void setUserColor() {
int userRed = 0;
int userGrn = 0;
int userBlu = 0;
this.userColor = new Color(userRed, userGrn, userBlu);
}
public void setUserColor(int red, int green, int blue) {
this.userColor = new Color(red, green, blue);
}
public Color getRandomColor() {
return randomColor;
}
public void setRandomColor() {
int randRed = (random.nextInt(17) + 1) * 15;
int randGrn = (random.nextInt(17) + 1) * 15;
int randBlu = (random.nextInt(17) + 1) * 15;
this.randomColor = new Color(randRed, randGrn, randBlu);
}
}
GameModel
is a plain Java class that holds the data for the game. In this simple game, we have two color fields, one for the random color and one for the user to adjust using the GUI buttons.
We moved the color initiation code to this class.
We have two setRandomColor
methods, one to initialize the user color, and one to set the user color based on the GUI button actions.
Now that we've created a working game model, we can focus on the view. Here's the view code.
public class GuessColor {
private GameModel model;
private JFrame frame;
private JPanel userPanel;
public GuessColor() {
this.model = new GameModel();
this.model.createColors();
frame = new JFrame("Match the color!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
printSolution();
}
// sets up the frame and functionality of UI
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
JLabel title = new JLabel("Match The Color!", JLabel.CENTER);
Font font = new Font("Times New Roman", Font.BOLD, 30);
title.setFont(font);
title.setBackground(Color.BLACK);
title.setForeground(Color.WHITE);
title.setOpaque(true);
panel.add(title, BorderLayout.NORTH);
JPanel center = new JPanel(new BorderLayout());
center.setBackground(Color.CYAN);
panel.add(center, BorderLayout.CENTER);
Dimension d = new Dimension(500, 500); // color panel size
JPanel randPan = new JPanel(); // random color panel
randPan.setBackground(model.getRandomColor());
randPan.setPreferredSize(d);
center.add(randPan, BorderLayout.WEST);
userPanel = new JPanel(); // adjustable color panel
userPanel.setBackground(model.getUserColor());
userPanel.setPreferredSize(d);
center.add(userPanel, BorderLayout.EAST);
/** BUTTONS **/
JPanel buttonPanel = new JPanel();
panel.add(buttonPanel, BorderLayout.SOUTH);
// This Object array makes it possible to create the JButtons in a loop
// buttonObject[0] - JButton labels
// buttonObject[1] - JButton action commands
// buttonObject[2] - JButton background colors
// buttonObject[3] - JButton foreground colors
Object[][] buttonObject = new Object[][] { { "+", "-", "+", "-", "+", "-" },
{ "red", "red", "green", "green", "blue", "blue" },
{ Color.RED, Color.RED, Color.GREEN,
Color.GREEN, Color.BLUE, Color.BLUE },
{ Color.WHITE, Color.WHITE, Color.BLACK,
Color.BLACK, Color.WHITE, Color.WHITE } };
Dimension b = new Dimension(50, 50); // button size
ButtonListener listener = new ButtonListener();
for (int i = 0; i < buttonObject[0].length; i++) {
JButton button = new JButton((String) buttonObject[0][i]);
button.setActionCommand((String) buttonObject[1][i]);
button.setBackground((Color) buttonObject[2][i]);
button.setForeground((Color) buttonObject[3][i]);
button.setPreferredSize(b);
button.setFocusPainted(false);
button.addActionListener(listener);
buttonPanel.add(button);
}
return panel;
}
public void setUserPanelColor() {
userPanel.setBackground(model.getUserColor());
}
public void printSolution() {
// This is just to show what the RGB
// values are so you can easily solve
System.out.println("SOLUTION: " + model.getRandomColor());
}
// main method
public static void main(String[] args) {
try {
String laf = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(laf);
} catch (Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GuessColor();
}
});
}
}
I made quite a few changes to your code. Here are the major changes I want to emphasize.
In the main
method, I added an e.printStackTrace();
to the catch
block. You should always print or log errors.
I separated the code to construct the JFrame
from the code to construct the main JPanel
. This allows me to focus on one part of the GUI at a time.
I used a JFrame
. The only time you should extend a Swing component, or any Java class, is when you want to override one or more of the class methods.
I moved almost all of the GuessColor
class variables to their respective methods. The only class variables that remain as class variables are the variables used in more than one method.
I created an admittedly complex Object
array so I could create the JButtons
in a loop.
Finally, I created the ActionListener
. I was able to move the check
method in the ActionListener
.
public class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
String text = button.getText();
String action = event.getActionCommand();
Color color = model.getUserColor();
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
if (action.equals("red")) {
if (text.equals("+")) {
red += 15;
red = Math.min(255, red);
model.setUserColor(red, green, blue);
} else {
red -= 15;
red = Math.max(0, red);
model.setUserColor(red, green, blue);
}
} else if (action.equals("green")) {
if (text.equals("+")) {
green += 15;
green = Math.min(255, green);
model.setUserColor(red, green, blue);
} else {
green -= 15;
green = Math.max(0, green);
model.setUserColor(red, green, blue);
}
} else if (action.equals("blue")) {
if (text.equals("+")) {
blue += 15;
blue = Math.min(255, blue);
model.setUserColor(red, green, blue);
} else {
blue -= 15;
blue = Math.max(0, blue);
model.setUserColor(red, green, blue);
}
}
setUserPanelColor();
System.out.println(model.getUserColor());
check();
}
// checks if the color panels are the same and displays
// winning message if they are the same
private void check() {
if (model.getRandomColor().equals(model.getUserColor())) {
int choose = JOptionPane.showConfirmDialog(frame,
"You win! Play again?");
if (choose == JOptionPane.YES_OPTION) {
model.createColors();
setUserPanelColor();
printSolution();
} else if (choose == JOptionPane.NO_OPTION) {
System.exit(0);
}
}
}
}
Here's the complete runnable code. I hope this explanation helps you.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class GuessColor {
private GameModel model;
private JFrame frame;
private JPanel userPanel;
public GuessColor() {
this.model = new GameModel();
this.model.createColors();
frame = new JFrame("Match the color!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
printSolution();
}
// sets up the frame and functionality of UI
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
JLabel title = new JLabel("Match The Color!", JLabel.CENTER);
Font font = new Font("Times New Roman", Font.BOLD, 30);
title.setFont(font);
title.setBackground(Color.BLACK);
title.setForeground(Color.WHITE);
title.setOpaque(true);
panel.add(title, BorderLayout.NORTH);
JPanel center = new JPanel(new BorderLayout());
center.setBackground(Color.CYAN);
panel.add(center, BorderLayout.CENTER);
Dimension d = new Dimension(500, 500); // color panel size
JPanel randPan = new JPanel(); // random color panel
randPan.setBackground(model.getRandomColor());
randPan.setPreferredSize(d);
center.add(randPan, BorderLayout.WEST);
userPanel = new JPanel(); // adjustable color panel
userPanel.setBackground(model.getUserColor());
userPanel.setPreferredSize(d);
center.add(userPanel, BorderLayout.EAST);
/** BUTTONS **/
JPanel buttonPanel = new JPanel();
panel.add(buttonPanel, BorderLayout.SOUTH);
// This Object array makes it possible to create the JButtons in a loop
// buttonObject[0] - JButton labels
// buttonObject[1] - JButton action commands
// buttonObject[2] - JButton background colors
// buttonObject[3] - JButton foreground colors
Object[][] buttonObject = new Object[][] { { "+", "-", "+", "-", "+", "-" },
{ "red", "red", "green", "green", "blue", "blue" },
{ Color.RED, Color.RED, Color.GREEN,
Color.GREEN, Color.BLUE, Color.BLUE },
{ Color.WHITE, Color.WHITE, Color.BLACK,
Color.BLACK, Color.WHITE, Color.WHITE } };
Dimension b = new Dimension(50, 50); // button size
ButtonListener listener = new ButtonListener();
for (int i = 0; i < buttonObject[0].length; i++) {
JButton button = new JButton((String) buttonObject[0][i]);
button.setActionCommand((String) buttonObject[1][i]);
button.setBackground((Color) buttonObject[2][i]);
button.setForeground((Color) buttonObject[3][i]);
button.setPreferredSize(b);
button.setFocusPainted(false);
button.addActionListener(listener);
buttonPanel.add(button);
}
return panel;
}
public void setUserPanelColor() {
userPanel.setBackground(model.getUserColor());
}
public void printSolution() {
// This is just to show what the RGB
// values are so you can easily solve
System.out.println("SOLUTION: " + model.getRandomColor());
}
// main method
public static void main(String[] args) {
try {
String laf = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(laf);
} catch (Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GuessColor();
}
});
}
public class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
String text = button.getText();
String action = event.getActionCommand();
Color color = model.getUserColor();
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
if (action.equals("red")) {
if (text.equals("+")) {
red += 15;
red = Math.min(255, red);
model.setUserColor(red, green, blue);
} else {
red -= 15;
red = Math.max(0, red);
model.setUserColor(red, green, blue);
}
} else if (action.equals("green")) {
if (text.equals("+")) {
green += 15;
green = Math.min(255, green);
model.setUserColor(red, green, blue);
} else {
green -= 15;
green = Math.max(0, green);
model.setUserColor(red, green, blue);
}
} else if (action.equals("blue")) {
if (text.equals("+")) {
blue += 15;
blue = Math.min(255, blue);
model.setUserColor(red, green, blue);
} else {
blue -= 15;
blue = Math.max(0, blue);
model.setUserColor(red, green, blue);
}
}
setUserPanelColor();
System.out.println(model.getUserColor());
check();
}
// checks if the color panels are the same and displays
// winning message if they are the same
private void check() {
if (model.getRandomColor().equals(model.getUserColor())) {
int choose = JOptionPane.showConfirmDialog(frame,
"You win! Play again?");
if (choose == JOptionPane.YES_OPTION) {
model.createColors();
setUserPanelColor();
printSolution();
} else if (choose == JOptionPane.NO_OPTION) {
System.exit(0);
}
}
}
}
public class GameModel {
private Color randomColor;
private Color userColor;
private final Random random;
public GameModel() {
this.random = new Random();
}
public void createColors() {
setRandomColor();
setUserColor();
}
public Color getUserColor() {
return userColor;
}
public void setUserColor() {
int userRed = 0;
int userGrn = 0;
int userBlu = 0;
this.userColor = new Color(userRed, userGrn, userBlu);
}
public void setUserColor(int red, int green, int blue) {
this.userColor = new Color(red, green, blue);
}
public Color getRandomColor() {
return randomColor;
}
public void setRandomColor() {
int randRed = (random.nextInt(17) + 1) * 15;
int randGrn = (random.nextInt(17) + 1) * 15;
int randBlu = (random.nextInt(17) + 1) * 15;
this.randomColor = new Color(randRed, randGrn, randBlu);
}
}
}
Edited to add: I made the game more accessible to younger players by adding an RGB display for each color.
Here's the GUI.

Here's the revised complete runnable code.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class GuessColor {
private DisplayPanel randomDisplayPanel;
private DisplayPanel userDisplayPanel;
private GameModel model;
private JFrame frame;
private JPanel randomPanel;
private JPanel userPanel;
public GuessColor() {
this.model = new GameModel();
this.model.createColors();
frame = new JFrame("Match the color!");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setResizable(false);
frame.setVisible(true);
}
// sets up the frame and functionality of UI
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
JLabel title = new JLabel("Match The Color!", JLabel.CENTER);
Font font = new Font("Times New Roman", Font.BOLD, 30);
title.setFont(font);
title.setBackground(Color.BLACK);
title.setForeground(Color.WHITE);
title.setOpaque(true);
panel.add(title, BorderLayout.NORTH);
JPanel center = new JPanel(new BorderLayout());
center.setBackground(Color.CYAN);
panel.add(center, BorderLayout.CENTER);
Dimension d = new Dimension(500, 500); // color panel size
randomPanel = new JPanel(new BorderLayout()); // random color panel
randomPanel.setBackground(model.getRandomColor());
randomPanel.setPreferredSize(d);
randomDisplayPanel = new DisplayPanel(model.getRandomColor());
randomPanel.add(randomDisplayPanel.getPanel(), BorderLayout.NORTH);
center.add(randomPanel, BorderLayout.WEST);
userPanel = new JPanel(new BorderLayout()); // adjustable color panel
userPanel.setBackground(model.getUserColor());
userPanel.setPreferredSize(d);
userDisplayPanel = new DisplayPanel(model.getUserColor());
userPanel.add(userDisplayPanel.getPanel(), BorderLayout.NORTH);
center.add(userPanel, BorderLayout.EAST);
/** BUTTONS **/
JPanel buttonPanel = new JPanel();
panel.add(buttonPanel, BorderLayout.SOUTH);
// This Object array makes it possible to create the JButtons in a loop
// buttonObject[0] - JButton labels
// buttonObject[1] - JButton action commands
// buttonObject[2] - JButton background colors
// buttonObject[3] - JButton foreground colors
Object[][] buttonObject = new Object[][] { { "+", "-", "+", "-", "+", "-" },
{ "red", "red", "green", "green", "blue", "blue" },
{ Color.RED, Color.RED, Color.GREEN,
Color.GREEN, Color.BLUE, Color.BLUE },
{ Color.WHITE, Color.WHITE, Color.BLACK,
Color.BLACK, Color.WHITE, Color.WHITE } };
Dimension b = new Dimension(50, 50); // button size
ButtonListener listener = new ButtonListener();
for (int i = 0; i < buttonObject[0].length; i++) {
JButton button = new JButton((String) buttonObject[0][i]);
button.setActionCommand((String) buttonObject[1][i]);
button.setBackground((Color) buttonObject[2][i]);
button.setForeground((Color) buttonObject[3][i]);
button.setPreferredSize(b);
button.setFocusPainted(false);
button.addActionListener(listener);
buttonPanel.add(button);
}
return panel;
}
public void setRandomPanelColor() {
randomPanel.setBackground(model.getRandomColor());
randomDisplayPanel.setColor(model.getRandomColor());
}
public void setUserPanelColor() {
userPanel.setBackground(model.getUserColor());
userDisplayPanel.setColor(model.getUserColor());
}
// main method
public static void main(String[] args) {
try {
String laf = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(laf);
} catch (Exception e) {
e.printStackTrace();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GuessColor();
}
});
}
public class DisplayPanel {
private JPanel panel;
private JTextField redField;
private JTextField greenField;
private JTextField blueField;
public DisplayPanel(Color color) {
createJPanel();
setColor(color);
}
private void createJPanel() {
panel = new JPanel(new GridBagLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.LINE_START;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(5, 5, 5, 5);
gbc.gridx = 0;
gbc.gridy = 0;
JLabel redLabel = new JLabel("Red:");
redLabel.setForeground(Color.WHITE);
panel.add(redLabel, gbc);
gbc.gridx++;
redField = new JTextField(3);
redField.setEditable(false);
redField.setHorizontalAlignment(JTextField.TRAILING);
panel.add(redField, gbc);
gbc.gridx = 0;
gbc.gridy++;
JLabel greenLabel = new JLabel("Green:");
greenLabel.setForeground(Color.WHITE);
panel.add(greenLabel, gbc);
gbc.gridx++;
greenField = new JTextField(3);
greenField.setEditable(false);
greenField.setHorizontalAlignment(JTextField.TRAILING);
panel.add(greenField, gbc);
gbc.gridx = 0;
gbc.gridy++;
JLabel blueLabel = new JLabel("Blue:");
blueLabel.setForeground(Color.WHITE);
panel.add(blueLabel, gbc);
gbc.gridx++;
blueField = new JTextField(3);
blueField.setEditable(false);
blueField.setHorizontalAlignment(JTextField.TRAILING);
panel.add(blueField, gbc);
}
public JPanel getPanel() {
return panel;
}
public void setColor(Color color) {
panel.setBackground(color);
redField.setText(Integer.toString(color.getRed()));
greenField.setText(Integer.toString(color.getGreen()));
blueField.setText(Integer.toString(color.getBlue()));
}
}
public class ButtonListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent event) {
JButton button = (JButton) event.getSource();
String text = button.getText();
String action = event.getActionCommand();
Color color = model.getUserColor();
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
if (action.equals("red")) {
if (text.equals("+")) {
red += 15;
red = Math.min(255, red);
} else {
red -= 15;
red = Math.max(0, red);
}
} else if (action.equals("green")) {
if (text.equals("+")) {
green += 15;
green = Math.min(255, green);
} else {
green -= 15;
green = Math.max(0, green);
}
} else if (action.equals("blue")) {
if (text.equals("+")) {
blue += 15;
blue = Math.min(255, blue);
} else {
blue -= 15;
blue = Math.max(0, blue);
}
}
model.setUserColor(red, green, blue);
setUserPanelColor();
check();
}
// checks if the color panels are the same and displays
// winning message if they are the same
private void check() {
if (model.getRandomColor().equals(model.getUserColor())) {
int choose = JOptionPane.showConfirmDialog(frame,
"You win! Play again?");
if (choose == JOptionPane.YES_OPTION) {
model.createColors();
setRandomPanelColor();
setUserPanelColor();
} else if (choose == JOptionPane.NO_OPTION) {
frame.dispose();
System.exit(0);
}
}
}
}
public class GameModel {
private Color randomColor;
private Color userColor;
private final Random random;
public GameModel() {
this.random = new Random();
}
public void createColors() {
setRandomColor();
setUserColor();
}
public Color getUserColor() {
return userColor;
}
public void setUserColor() {
int userRed = 135;
int userGrn = 135;
int userBlu = 135;
this.userColor = new Color(userRed, userGrn, userBlu);
}
public void setUserColor(int red, int green, int blue) {
this.userColor = new Color(red, green, blue);
}
public Color getRandomColor() {
return randomColor;
}
public void setRandomColor() {
int randRed = (random.nextInt(17) + 1) * 15;
int randGrn = (random.nextInt(17) + 1) * 15;
int randBlu = (random.nextInt(17) + 1) * 15;
this.randomColor = new Color(randRed, randGrn, randBlu);
}
}
}