Final local variable error - java

I'm basically making a tic tac toe game, with AI and all, and my system is to draw the buttons, and have a Boolean assigned to each button, where it is assigned to true if it's taken by an X, or false if it's empty. It draws out to the correct size and layout and all but in my action listeners it gives me the error:
Edit: removed the finals, still giving the error
"The final local variable cannot be assigned since it is defined in an
enclosing type."
when I change the boolean to true after assigning the button text to 'x'.
package myClass;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
public class mainClass {
public static void main(String[] args) {
//create window
JFrame mainWindow = new JFrame("Tic Tac Toe");
//properties of mainWindow
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setSize(600, 600); // buttons will fill entirely, 200x200 buttons
mainWindow.setLayout(new GridLayout(3, 3));
//create buttons
JButton topLeft = new JButton("");
JButton topMid = new JButton("");
JButton topRight = new JButton("");
JButton midLeft = new JButton("");
JButton midMid = new JButton("");
JButton midRight = new JButton("");
JButton botLeft = new JButton("");
JButton botMid = new JButton("");
JButton botRight = new JButton("");
//checker for if the button already has a character
boolean tmid = false;
boolean tright = false;
boolean mleft = false;
boolean mmid = false;
boolean mright = false;
boolean bleft = false;
boolean bmid = false;
boolean bright = false;
//button properties
Dimension buttonSize = new Dimension(200,200);
topLeft.setSize(buttonSize);
topMid.setSize(buttonSize);
topRight.setSize(buttonSize);
midLeft.setSize(buttonSize);
midMid.setSize(buttonSize);
midRight.setSize(buttonSize);
botLeft.setSize(buttonSize);
botMid.setSize(buttonSize);
botRight.setSize(buttonSize);
//Action listener
topLeft.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if(tleft == false){
topLeft.setText("X");
tleft = true;
}
}
});
topMid.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if(tmid == false){
topMid.setText("X");
tmid = true;
}
}
});
topRight.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if(tright == false){
topRight.setText("X");
tright = true;
}
}
});
midLeft.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if(mleft == false){
midLeft.setText("X");
mleft = true;
}
}
});
midMid.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if(mmid == false){
midMid.setText("X");
mmid = true;
}
}
});
midRight.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if(mright == false){
midRight.setText("X");
mright = true;
}
}
});
botLeft.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if(bleft == false){
botLeft.setText("X");
bleft = true;
}
}
});
botMid.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if(bmid == false){
botMid.setText("X");
bmid = true;
}
}
});
botRight.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if(bright == false){
botRight.setText("X");
bright = true;
}
}
});
//draw components
mainWindow.add(topLeft);
mainWindow.add(topMid);
mainWindow.add(topRight);
mainWindow.add(midLeft);
mainWindow.add(midMid);
mainWindow.add(midRight);
mainWindow.add(botLeft);
mainWindow.add(botMid);
mainWindow.add(botRight);
mainWindow.setVisible(true); // draw it
}
}

There are two problems. One, you cannot modify final variables. Two, you have to use final variables to have scope within the listeners. This code needs serious refactoring. However, here is a quick solution that requires minimal intervention.
Remove all of the boolean tleft; boolean tmid; ... variables
Add this enum outside of the main() method definition
enum ESide {
tleft, tmid, tright,
mleft, mmid, mright,
bleft, bmid, bright,
};
Add this definition at the appropriate spot
// checker for if the button already has a character
final Map<ESide, Boolean> board = new HashMap<>();
for (ESide side : ESide.values()) {
board.put(side, false);
}
Replace the listeners with the following, adjusting the tleft as appropriate. However, seriously consider making a method that returns the mouse adapter.
public void mouseClicked(java.awt.event.MouseEvent evt)
{
if (board.get(ESide.tleft).booleanValue() == false) {
topLeft.setText("X");
board.put(ESide.tleft, true);
}
}
The error you are receiving will be eliminated.

Related

Mouse event goes through the component

I have added a simple program to illustrate.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SimpleInternalFrame extends Frame
{
private static final long serialVersionUID = 1L;
static JLayeredPane desktop;
JInternalFrame internalFrame;
public SimpleInternalFrame()
{
super("Internal Frame Demo");
setSize(500, 400);
Panel p = new Panel();
add(p, BorderLayout.SOUTH);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
desktop = new JDesktopPane();
desktop.setOpaque(true);
add(desktop, BorderLayout.CENTER);
}
public static void main(String args[])
{
SimpleInternalFrame sif = new SimpleInternalFrame();
sif.setVisible(true);
final JInternalFrame internalFrame = new JInternalFrame("Internal Frame 1", true, true, true, true);
internalFrame.setBounds(50, 50, 300, 200);
desktop.add(internalFrame, new Integer(1));
JTextField tf = new JTextField();
tf.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent evt)
{
System.out.println("Text Field " + evt.getClickCount());
}
});
internalFrame.add(tf);
internalFrame.setVisible(true);
final JInternalFrame internalFrame2 = new JInternalFrame("Internal Frame 1", true, true, true, true);
internalFrame2.setBounds(50, 50, 200, 100);
desktop.add(internalFrame2, new Integer(1));
JButton jb = new JButton("click me");
jb.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent evt)
{
if (evt.getClickCount() == 1)
{
System.out.println("Button " + evt.getClickCount());
internalFrame2.setVisible(false);
}
}
});
internalFrame2.add(jb);
internalFrame2.setVisible(true);
}
}
When running the code it will open a two internal frames.One has button.One has text field.Button will close the first Internal frame for single click.
Double click the button.It will show click count 2 as in text field.
This is the problem we have currently in the project.Thing is second frame dose not has text field in actual project.It has click-able item that work in double click event.
This is the problem we have currently.Please help.
tf.addMouseListener(new MouseAdapter() {
int cc;
public void mouseClicked(MouseEvent evt) {
int ccount = evt.getClickCount();
if(ccount == 1 || ccount == cc+1) {
cc = ccount;
System.out.println("Text Field " + evt.getClickCount());
}
}
});
This will work more than once.
Another possibility is to use components with overriden processMouseEvent():
public class SimpleInternalFrame extends Frame {
...
private MouseEvent lastMouseEvent;
public boolean checkEvent(MouseEvent e) {
if(lastMouseEvent != null) {
if(lastMouseEvent.getSource() != e.getSource()) {
if(e.getClickCount() != 1) {
return false;
}
}
}
lastMouseEvent = e;
return true;
}
class MTextField extends JTextField {
protected void processMouseEvent(MouseEvent e) {
if (checkEvent(e)) {
super.processMouseEvent(e);
}
}
}
class MButton extends JButton {
protected void processMouseEvent(MouseEvent e) {
if (checkEvent(e)) {
super.processMouseEvent(e);
}
}
}
public JTextField createText() {
return new MTextField();
}
public MButton createButton() {
return new MButton();
}
} //end of SimpleInternalFrame
create components:
final JTextField tf = sif.createText();
tf.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
System.out.println("Text Field " + evt.getClickCount());
}
});
JButton jb = sif.createButton();
jb.setText("click me");
jb.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
if (evt.getClickCount() == 1) {
internalFrame2.setVisible(false);
}
}
});
You can use a static boolean called myTurn initialized to false and then in the textfield mouseClicked:
tf.addMouseListener(new MouseAdapter()
{
public void mouseClicked(MouseEvent evt)
{
if (evt.getClickCount() >= 2 && !myTurn) {
myTurn = true;
evt.consume();
} else {
myTurn = true; //Initial one click on me
System.out.println("Text Field " + evt.getClickCount());
evt.consume();
}
}
});
This solves your problem in this basic case, but I don't know if it will in your application. The problem is that if you click the TextField before the Button, you can experience the same problem. However, if that isn't possible, this will solve it.
While searching on internet and reading some documents i was able get a solution.
int timerinterval = (int) Toolkit.getDefaultToolkit().
getDesktopProperty("awt.multiClickInterval");
final Timer timer = new Timer(timerinterval, new ActionListener()
{
public void actionPerformed(ActionEvent acEvt)
{
internalFrame2.setVisible(false);
}
});
jb.addMouseListener(new MouseAdapter()
{
public void mouseClicked(final MouseEvent evt)
{
System.out.println("Button " + evt.getClickCount());
timer.setRepeats(false);
timer.start();
if (evt.getClickCount() > 1)
{
timer.restart();
}
}
});
One draw back of this solution is if user do a single click he need to wait
timerinterval unnecessarily.Any one has better solution please post.

Setting up KeyListeners using the MVC in java

I am trying to make myself a calculator in Java. I figured it would be best to implement the MVC (model view controller) design for my code. I have some of the basics working, the calculator does actually work, the issue is i cannot figure out where i am going wrong with the implementation of listening to keys. At the moment i have the ability to click on the buttons using the action listener and updating the field with a numeric value and the buttons to add, subtract, multiply, divide and also to clear. So really the only thing on my mind at the moment is trying to allow the user (myself) the option to use the number pad on the keyboard to append values to the field, anyways here is my code.
This the view
package Calculator;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class CalcFrame extends JFrame{
private Dimension d = new Dimension(300,300);
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JButton equals = new JButton("=");
JButton addBtn = new JButton("+");
JButton subtractBtn = new JButton("-");
JButton multiplyBtn = new JButton("*");
JButton divideBtn = new JButton("/");
JTextArea field = new JTextArea(1,20);
JButton numBtn[] = new JButton[11];
String numTxt[] = {"0","1","2","3","4","5","6","7","8","9","C"};
Color newColor = new Color(10,70,40);
int x = 50, y = 0;
public CalcFrame(){
this.setSize(d);
this.setResizable(false);
// frame.setVisible(true);
this.setTitle("Marks Calculator");
this.setIconImage(new ImageIcon(this.getClass().getResource("emblem.png")).getImage());
for(int i = 0; i < numBtn.length; i++){
numBtn[i] = new JButton(numTxt[i]);
numBtn[i].setSize(50, 30);
}
for(int i = 0; i <numBtn.length; i++){
numBtn[0].setLocation(10,180);
numBtn[1].setLocation(10,140);
numBtn[2].setLocation(65,140);
numBtn[3].setLocation(120,140);
numBtn[4].setLocation(175,140);
numBtn[5].setLocation(10,100);
numBtn[6].setLocation(65,100);
numBtn[7].setLocation(120,100);
numBtn[8].setLocation(175,100);
numBtn[9].setLocation(10,60);
numBtn[10].setLocation(175,20);
panel2.add(numBtn[i]);
}
field.setLocation(10, 10);
field.setSize(280,30);
field.setEditable(false);
field.setFocusable(true);
panel1.setSize(300, 50);
panel1.setLayout(null);
this.add(panel1);
panel2.setSize(300, 250);
panel2.setBackground(newColor);
panel2.setLocation(0, 51);
panel2.setLayout(null);
this.add(panel2);
equals.setLocation(230,180);
equals.setSize(50, 30);
panel2.add(equals);
addBtn.setLocation(230, 140);
addBtn.setSize(50,30);
panel2.add(addBtn);
subtractBtn.setLocation(230, 100);
subtractBtn.setSize(50,30);
panel2.add(subtractBtn);
multiplyBtn.setLocation(230, 60);
multiplyBtn.setSize(50,30);
panel2.add(multiplyBtn);
divideBtn.setLocation(230, 20);
divideBtn.setSize(50,30);
panel2.add(divideBtn);
panel1.add(field);
this.setLocationRelativeTo(rootPane);
this.setLayout(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void addKeyL(KeyListener keyp){
addKeyListener(keyp);
}
public void addListener(ActionListener listener){
addBtn.addActionListener(listener);
subtractBtn.addActionListener(listener);
equals.addActionListener(listener);
multiplyBtn.addActionListener(listener);
divideBtn.addActionListener(listener);
for(int i = 0; i < numBtn.length; i++){
numBtn[i].addActionListener(listener);
}
}
public int getFieldText(){
return Integer.parseInt(field.getText());
}
public void setFieldText(){
field.setText("");
}
public void setAnswer(int solution){
field.setText(Integer.toString(solution));
}
}
this is the model
package Calculator;
public class Calculations {
private int total;
public void addNumbers(int a, int b){
total = a + b;
}
public void subtractNumbers(int a, int b){
total = a - b;
}
public void multiplyNumbers(int a, int b){
total = a * b;
}
public void divideNumbers(int a, int b){
total = a / b;
}
public int getTotal(){
return total;
}
}
and this is the controller
package Calculator;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class KeyEvents{
private boolean isAdd = false;
private boolean isSubtract = false;
private boolean isDivide = false;
private boolean isMultiply = false;
private CalcFrame view = new CalcFrame();
private Calculations model = new Calculations();
int a = 0, b = 0, answer;
int counter = 0;
public KeyEvents(CalcFrame view, Calculations model){
this.view = view;
this.model = model;
this.view.addListener(new CalcListener());
this.view.addKeyL(new CalcListener());
}
class CalcListener implements ActionListener, KeyListener{
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource().equals(view.addBtn)){
a = view.getFieldText();
view.field.setText("");
isAdd = true;
isSubtract = false;
isDivide = false;
isMultiply = false;
}
if(e.getSource().equals(view.numBtn[0])){
view.field.append("0");
}
if(e.getSource().equals(view.numBtn[1])){
view.field.append("1");
}
if(e.getSource().equals(view.numBtn[2])){
view.field.append("2");
}
if(e.getSource().equals(view.numBtn[3])){
view.field.append("3");
}
if(e.getSource().equals(view.numBtn[4])){
view.field.append("4");
}
if(e.getSource().equals(view.numBtn[5])){
view.field.append("5");
}
if(e.getSource().equals(view.numBtn[6])){
view.field.append("6");;
}
if(e.getSource().equals(view.numBtn[7])){
view.field.append("7");
}
if(e.getSource().equals(view.numBtn[8])){
view.field.append("8");
}
if(e.getSource().equals(view.numBtn[9])){
view.field.append("9");
}
if(e.getSource().equals(view.numBtn[10])){
view.field.setText("");
}
if(e.getSource().equals(view.subtractBtn)){
a = view.getFieldText();
view.field.setText("");
isAdd = false;
isSubtract = true;
isDivide = false;
isMultiply = false;
}
if(e.getSource().equals(view.multiplyBtn)){
a = view.getFieldText();
view.field.setText("");
isAdd = false;
isSubtract = false;
isDivide = false;
isMultiply = true;
}
if(e.getSource().equals(view.divideBtn)){
a = view.getFieldText();
view.field.setText("");
isAdd = false;
isSubtract = false;
isDivide = true;
isMultiply = false;
}
if(e.getSource().equals(view.equals)){
b = view.getFieldText();
if(isAdd == true){
view.setFieldText();
model.addNumbers(a, b);
view.setAnswer(model.getTotal());
}
if(isSubtract == true){
view.setFieldText();
model.subtractNumbers(a, b);
view.setAnswer(model.getTotal());
}
if(isMultiply == true){
view.setFieldText();
model.multiplyNumbers(a, b);
view.setAnswer(model.getTotal());
}
if(isDivide == true){
view.setFieldText();
model.divideNumbers(a, b);
view.setAnswer(model.getTotal());
}
}
}
#Override
public void keyTyped(KeyEvent e) {
if(e.getSource().equals(KeyEvent.VK_0)){
System.out.println("sjkdhlkj");
}
if(e.getSource().equals(KeyEvent.VK_1)){
view.field.append("1");
}
if(e.getSource().equals(KeyEvent.VK_2)){
view.field.append("2");
}
if(e.getSource().equals(KeyEvent.VK_3)){
view.field.append("3");
}
if(e.getSource().equals(KeyEvent.VK_4)){
view.field.append("4");
}
if(e.getSource().equals(KeyEvent.VK_5)){
view.field.append("5");
}
if(e.getSource().equals(KeyEvent.VK_6)){
view.field.append("6");
}
if(e.getSource().equals(KeyEvent.VK_7)){
view.field.append("7");
}
if(e.getSource().equals(KeyEvent.VK_8)){
view.field.append("8");
}
if(e.getSource().equals(KeyEvent.VK_9)){
view.field.append("9");
}
}
#Override
public void keyPressed(KeyEvent e) {
if(e.getSource().equals(KeyEvent.VK_0)){
System.out.println("sjkdhlkj");
}
if(e.getSource().equals(KeyEvent.VK_1)){
view.field.append("1");
}
if(e.getSource().equals(KeyEvent.VK_2)){
view.field.append("2");
}
if(e.getSource().equals(KeyEvent.VK_3)){
view.field.append("3");
}
if(e.getSource().equals(KeyEvent.VK_4)){
view.field.append("4");
}
if(e.getSource().equals(KeyEvent.VK_5)){
view.field.append("5");
}
if(e.getSource().equals(KeyEvent.VK_6)){
view.field.append("6");
}
if(e.getSource().equals(KeyEvent.VK_7)){
view.field.append("7");
}
if(e.getSource().equals(KeyEvent.VK_8)){
view.field.append("8");
}
if(e.getSource().equals(KeyEvent.VK_9)){
view.field.append("9");
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getSource().equals(KeyEvent.VK_0)){
System.out.println("sjkdhlkj");
}
if(e.getSource().equals(KeyEvent.VK_1)){
view.field.append("1");
}
if(e.getSource().equals(KeyEvent.VK_2)){
view.field.append("2");
}
if(e.getSource().equals(KeyEvent.VK_3)){
view.field.append("3");
}
if(e.getSource().equals(KeyEvent.VK_4)){
view.field.append("4");
}
if(e.getSource().equals(KeyEvent.VK_5)){
view.field.append("5");
}
if(e.getSource().equals(KeyEvent.VK_6)){
view.field.append("6");
}
if(e.getSource().equals(KeyEvent.VK_7)){
view.field.append("7");
}
if(e.getSource().equals(KeyEvent.VK_8)){
view.field.append("8");
}
if(e.getSource().equals(KeyEvent.VK_9)){
view.field.append("9");
}
}
}
}
the tl;dr of this is, i am unable to get keyListener to work correctly, i have tried assigning the keyListener to the field, panel1, panel2 and this. seperately. Assistance is appreciated as always.
~UPDATE~
I decided to give GitHub a try and have just put my code up on to it. I hope it would make my code easier to understand or even forkable so a person can mess around with it.
https://github.com/niroshido/TestCalculator/tree/master/Calculator
Use Key Bindings. A simple example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class CalculatorPanel extends JPanel
{
private JTextField display;
public CalculatorPanel()
{
Action numberAction = new AbstractAction()
{
#Override
public void actionPerformed(ActionEvent e)
{
display.setCaretPosition( display.getDocument().getLength() );
display.replaceSelection(e.getActionCommand());
}
};
setLayout( new BorderLayout() );
display = new JTextField();
display.setEditable( false );
display.setHorizontalAlignment(JTextField.RIGHT);
add(display, BorderLayout.NORTH);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout( new GridLayout(0, 5) );
add(buttonPanel, BorderLayout.CENTER);
for (int i = 0; i < 10; i++)
{
String text = String.valueOf(i);
JButton button = new JButton( text );
button.addActionListener( numberAction );
button.setBorder( new LineBorder(Color.BLACK) );
button.setPreferredSize( new Dimension(50, 50) );
buttonPanel.add( button );
KeyStroke pressed = KeyStroke.getKeyStroke(text);
InputMap inputMap = button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
inputMap.put(pressed, text);
button.getActionMap().put(text, numberAction);
}
}
private static void createAndShowUI()
{
// UIManager.put("Button.margin", new Insets(10, 10, 10, 10) );
JFrame frame = new JFrame("Calculator Panel");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.add( new CalculatorPanel() );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
You either need to make sure that whatever component you're adding the KeyListener to has the focus, or you should use key bindings instead.

java binding the keys correctly for a game

I am trying to move a rectangle up,down,left,right when up,down,left,right keys are pressed. I am puzzled why the key listeners no longer listen when the game is started..i.e when gameloop is started. Before starting the game or pressing "start" the listener works i.e it prints "up pressed" System.out.println("up pressed"); but when the game is started by clicking the start button then the listener no longer work. Why is this so? Appreciate any help!
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class GameLoopTest extends JFrame implements ActionListener
{
private GamePanel gamePanel = new GamePanel();
private JButton startButton = new JButton("Start");
private JButton quitButton = new JButton("Quit");
private JButton pauseButton = new JButton("Pause");
private boolean running = false;
private boolean paused = false;
private int fps = 60;
private int frameCount = 0;
public GameLoopTest()
{
super("Fixed Timestep Game Loop Test");
Container cp = getContentPane();
cp.setLayout(new BorderLayout());
JPanel p = new JPanel();
p.setLayout(new GridLayout(1,2));
p.add(startButton);
p.add(pauseButton);
p.add(quitButton);
cp.add(gamePanel, BorderLayout.CENTER);
cp.add(p, BorderLayout.SOUTH);
setSize(1000, 700);
startButton.addActionListener(this);
quitButton.addActionListener(this);
pauseButton.addActionListener(this);
Action handle_up_action_pressed = new AbstractAction(){
public void actionPerformed(ActionEvent e){
gamePanel.up_pressed= true;
System.out.println("up pressed");
}
};
Action handle_up_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
gamePanel.up_pressed= false;
}
};
Action handle_down_action_pressed = new AbstractAction(){
public void actionPerformed(ActionEvent e){
gamePanel.down_pressed= true;
}
};
Action handle_down_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
gamePanel.down_pressed= false;
}
};
Action handle_left_action_pressed = new AbstractAction(){
public void actionPerformed(ActionEvent e){
gamePanel.left_pressed= true;
}
};
Action handle_left_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
gamePanel.left_pressed= false;
}
};
Action handle_right_action_pressed = new AbstractAction(){
public void actionPerformed(ActionEvent e){
gamePanel.right_pressed= true;
}
};
Action handle_right_action_released = new AbstractAction(){
public void actionPerformed(ActionEvent e){
gamePanel.right_pressed= false;
}
};
gamePanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "handle_up_pressed");
gamePanel.getActionMap().put("handle_up_pressed", handle_up_action_pressed);
gamePanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "handle_up_released");
gamePanel.getActionMap().put("handle_up_released", handle_up_action_released);
gamePanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "handle_down_pressed");
gamePanel.getActionMap().put("handle_down_pressed", handle_down_action_pressed);
gamePanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "handle_down_released");
gamePanel.getActionMap().put("handle_down_released", handle_down_action_released);
gamePanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), "handle_left_pressed");
gamePanel.getActionMap().put("handle_left_pressed", handle_left_action_pressed);
gamePanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), "handle_left_released");
gamePanel.getActionMap().put("handle_left_released", handle_left_action_released);
gamePanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), "handle_right_pressed");
gamePanel.getActionMap().put("handle_right_pressed", handle_right_action_pressed);
gamePanel.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), "handle_right_released");
gamePanel.getActionMap().put("handle_right_released", handle_right_action_released);
}
public static void main(String[] args)
{
GameLoopTest glt = new GameLoopTest();
glt.setVisible(true);
}
public void actionPerformed(ActionEvent e)
{
Object s = e.getSource();
if (s == startButton)
{
running = !running;
if (running)
{
startButton.setText("Stop");
runGameLoop();
}
else
{
startButton.setText("Start");
}
}
else if (s == pauseButton)
{
paused = !paused;
if (paused)
{
pauseButton.setText("Unpause");
}
else
{
pauseButton.setText("Pause");
}
}
else if (s == quitButton)
{
System.exit(0);
}
}
//Starts a new thread and runs the game loop in it.
public void runGameLoop()
{
Thread loop = new Thread()
{
public void run()
{
gameLoop();
}
};
loop.start();
}

Game of Life in Java, Overpopulation but can't figure out why

This is homework. I included relevant code at the bottom.
Problem:
In an attempted to allow the user to resize the grid, the grid is now being drawn severely overpopuated.
Screen Shots:
"Overpopulation" -
http://i.imgur.com/zshAC6n.png
"Desired Population" -
http://i.imgur.com/5Rf6P42.png
Background:
It's a version of Conway's Game of Life. In class we completed 3 classes: LifeState which handles the game logic, LifePanel which is a JPanel that contains the game, and a driver that created a JFrame and added the LifePanel. The assignment was to develop it into a full GUI application with various requirements. My solution was to extend JFrame and do most of my work in that class.
Initializing the LifePanel outside of the actionlistener yields normal population, but intializing the LifePanel in the actionlistener "overpopulates" the grid.
Question: Why is the overpopulation occurring?
LifePanel class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
public class LifePanel extends JPanel implements MouseListener
{
private int row;
private int col;
private int scale;
private LifeState life;
boolean state;
boolean wrap;
int delay;
Timer timer;
public LifePanel(int r, int c, int s, int d)
{
row = r;
col = c;
scale = s;
delay = d;
life = new LifeState(row,col);
Random rnd = new Random();
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
life.setCell(i,j,rnd.nextBoolean());
timer = new Timer(delay, new UpdateListener());
setPreferredSize( new Dimension(scale*row, scale*col));
addMouseListener(this);
timer.start();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
if(life.getCell(i,j))
g.fillRect(scale*i,scale*j,scale,scale);
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public int getScale() {
return scale;
}
public void setScale(int scale) {
this.scale = scale;
}
public int getDelay() {
return delay;
}
public void setDelay(int delay) {
this.delay = delay;
timer.setDelay(delay);
}
public void pauseGame(){
timer.stop();
}
public void playGame(){
timer.restart();
}
public void setInitState(boolean set){
state = set;
if(state){
timer.stop();
}
}
public void setWrap(boolean set){
wrap = set;
if(wrap){
//implement allow wrap
}
}
#Override
public void mouseClicked(MouseEvent e) {
if(state){
int x=e.getX();
int y=e.getY();
boolean isFilled;
isFilled = life.getCell(x,y);
//Test pop-up
JOptionPane.showMessageDialog(this, x+","+y+"\n"+life.getCell(x,y));
if(isFilled){
life.setCell(x,y,false);
}else{
life.setCell(x,y,true);
}
repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
private class UpdateListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
life.iterate();
repaint();
}
}
}
LifeFrame class
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class LifeFrame extends JFrame implements ActionListener{
JMenuBar menuBar;
JMenu mainMenu, helpMenu;
JMenuItem restartItem, quitItem, helpItem;
JButton stopButton, playButton, pauseButton, startButton;
CardLayout cardLayout = new MyCardLayout();
CardLayout cardLayout2 = new MyCardLayout();
SetupPanel setupPanel; //panel for input
LifePanel gamePanel; //game panel
JPanel controls = new JPanel(); //controls for game
JPanel controls2 = new JPanel(); //controls for input panel
JPanel cardPanel = new JPanel(cardLayout);
JPanel cardPanel2 = new JPanel(cardLayout2);
int gridRow=480;
int gridCol=480;
int scale=1;
int delay=2;
boolean setState = false;
boolean setWrap = false;
public LifeFrame() {
setTitle("Game of Life");
setLayout(new BorderLayout());
//Add the Panels
setupPanel = new SetupPanel();
gamePanel = new LifePanel(gridRow,gridCol,scale,delay);
cardPanel.add(setupPanel, "1");
cardPanel.add(gamePanel, "2");
add(cardPanel, BorderLayout.NORTH);
cardPanel2.add(controls2, "1");
cardPanel2.add(controls, "2");
add(cardPanel2, BorderLayout.SOUTH);
//init menu
menuBar = new JMenuBar();
//button listener setup
stopButton = new JButton("Stop");
pauseButton = new JButton("Pause");
playButton = new JButton("Play");
startButton = new JButton("Start");
stopButton.addActionListener(this);
pauseButton.addActionListener(this);
playButton.addActionListener(this);
startButton.addActionListener(this);
//menu listener setup
restartItem = new JMenuItem("Restart", KeyEvent.VK_R);
quitItem = new JMenuItem("Quit", KeyEvent.VK_Q);
helpItem = new JMenuItem("Help", KeyEvent.VK_H);
restartItem.addActionListener(this);
quitItem.addActionListener(this);
helpItem.addActionListener(this);
//add buttons
controls.add(stopButton);
controls.add(pauseButton);
controls.add(playButton);
controls2.add(startButton);
//build the menus
mainMenu = new JMenu("Menu");
mainMenu.setMnemonic(KeyEvent.VK_M);
helpMenu = new JMenu("Help");
helpMenu.setMnemonic(KeyEvent.VK_H);
menuBar.add(mainMenu);
menuBar.add(helpMenu);
setJMenuBar(menuBar);
//add JMenuItems
restartItem.getAccessibleContext().setAccessibleDescription("Return to setup screen");
mainMenu.add(restartItem);
mainMenu.add(quitItem);
helpMenu.add(helpItem);
this.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
pack();
setLocationRelativeTo(null);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
#Override
public void actionPerformed(ActionEvent e) {
try{
gridRow = setupPanel.getRowSize();
gridCol = setupPanel.getColSize();
scale = setupPanel.getScale();
delay = setupPanel.getDelay();
setWrap = setupPanel.getSetWrap();
setState = setupPanel.getSetState();
}catch (NumberFormatException n){
JOptionPane.showMessageDialog(LifeFrame.this, "Make sure the fields contain only digits and are completed!");
return;
}
if(e.getSource() == pauseButton){
gamePanel.pauseGame();
}else if(e.getSource() == playButton){
gamePanel.playGame();
}else if(e.getSource() == quitItem){
System.exit(0);
}else if(e.getSource() == restartItem || e.getSource() == stopButton){
cardLayout.show(cardPanel, "1");
cardLayout2.show(cardPanel2, "1");
pack();
setLocationRelativeTo(null);
}else if(e.getSource() == helpItem){
String helpText = "Help\nPlease make sure every field is completed and contains only digits\nCurrent Stats:\nGrid Size: "+gamePanel.getRow()+" by "+gamePanel.getCol()+"\nScale: "+ gamePanel.getScale() +"\nDelay: "+gamePanel.getDelay()+"\nManual Initial State: "+setState+"\nEnable Wrapping: "+setWrap;
JOptionPane.showMessageDialog(LifeFrame.this, helpText);
}else if(e.getSource() == startButton){
gamePanel = new LifePanel(gridRow,gridCol,scale,delay);
cardPanel.add(gamePanel, "2");
/*
* Alternate solution, throws array index out of bounds due to array usage in the LifePanel, but properly
* populates the grid.
*
gamePanel.setRow(gridRow);
gamePanel.setCol(gridCol);
gamePanel.setScale(scale);
gamePanel.setDelay(delay);
*/
if(setWrap){
gamePanel.setWrap(true);
gamePanel.playGame();
}else if(setState){
gamePanel.setInitState(true);
}else{
gamePanel.setWrap(false);
gamePanel.setInitState(false);
gamePanel.playGame();
}
gamePanel.repaint();
cardLayout.show(cardPanel, "2");
cardLayout2.show(cardPanel2, "2");
pack();
setLocationRelativeTo(null);
}
}
public static class MyCardLayout extends CardLayout {
#Override
public Dimension preferredLayoutSize(Container parent) {
Component current = findCurrentComponent(parent);
if (current != null) {
Insets insets = parent.getInsets();
Dimension pref = current.getPreferredSize();
pref.width += insets.left + insets.right;
pref.height += insets.top + insets.bottom;
return pref;
}
return super.preferredLayoutSize(parent);
}
public Component findCurrentComponent(Container parent) {
for (Component comp : parent.getComponents()) {
if (comp.isVisible()) {
return comp;
}
}
return null;
}
}
}
Thanks for reading all this, and in advance for any help/advice you offer.
EDIT: Added screen shots and refined question.
Based on how you initialize LifePanel
Random rnd = new Random();
for(int i=0;i<row;i++)
for(int j=0;j<col;j++)
life.setCell(i,j,rnd.nextBoolean());
what you call "overpopulation" is the expected state. The above code will set about 1/2 of the cells to "alive" (or "occupied"), which is what your "overpopulated" state looks like.
The "desired population" screenshot contains many "life" artifacts such as "beehives", "gliders", "traffic lights", etc, and was either manually constructed or is the result of running several iterations on an initially 50% random population. With a 50% occupied population the first generation will result in wholesale clearing ("death") of many, many cells due to the proximity rules.
Most crucially, consider that, when starting up, your program does not paint the initial configuration. At least one iteration occurs before the first repaint() call.
I don't think your code is broken at all, just your expectation for what the initial population looks like.

Generate a double click mouse event in Java Swing

I am trying to generate a double click mouse event on the EDT as follows:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
component.dispatchEvent(new MouseEvent(
component,
MouseEvent.MOUSE_CLICKED,
System.currentTimeMillis(),
InputEvent.BUTTON1_MASK,
x, y,
2, // click count
false
));
}
});
This does not seem to dispatch a double click event, even though I am setting the click count to 2.
Any suggestions or examples?
Considering:
final JButton clickTwiceButton = new JButton();
final JButton fireEventButton = new JButton();
Listeners:
clickTwiceButton.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseClicked(java.awt.event.MouseEvent evt) {
if (evt.getClickCount() == 2) {
JOptionPane.showMessageDialog(null, "Double clicked!");
}
}
});
fireEventButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
// Invoking later for no reason, just to simulate your code
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
clickTwiceButton.dispatchEvent(new MouseEvent(
fireEventButton,
MouseEvent.MOUSE_CLICKED,
1,
MouseEvent.BUTTON1,
0, 0,
2,
false
));
}
});
}
});
When I click fireEventButton the MouseEvent gets correctly dispatched to clickTwiceButton, and the dialog appears as expected.
So, as #Andrew pointed out, the problem seems to be that either you are firing the event to the wrong component or that something is not right with the registered MouseListener / MouseAdapter code.
Use component.getMouseListeners() to check for your component Listeners and debug the code that handles its events.
The method is very simple. You should get the time of the first click and the time of the second click, then you can do a condition in between.
Method code as below:
private boolean state=false;
private long first_pressed;
JButton btnAdd = new JButton("add");
btnAdd.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
if(state==false) {
first_pressed=e.getWhen();
state=true;
}
if(first_pressed!=e.getWhen())
{
JOptionPane.showConfirmDialog(null,"doubel click","Click",JOptionPane.YES_NO_OPTION);
state=false;
}
}
});
public class TestMouseListener implements MouseListener {
private boolean leftClick;
private int clickCount;
private boolean doubleClick;
private boolean tripleClick;
public void mouseClicked(MouseEvent evt) {
if (evt.getButton()==MouseEvent.BUTTON1){
leftClick = true; clickCount = 0;
if(evt.getClickCount() == 2) doubleClick=true;
if(evt.getClickCount() == 3){
doubleClick = false;
tripleClick = true;
}
Integer timerinterval = (Integer)Toolkit.getDefaultToolkit().getDesktopProperty("awt.multiClickInterval");
Timer timer = new Timer(timerinterval, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
if(doubleClick){
System.out.println("double click.");
clickCount++;
if(clickCount == 2){
doubleClick(); //your doubleClick method
clickCount=0;
doubleClick = false;
leftClick = false;
}
}else if (tripleClick) {
System.out.println("Triple Click.");
clickCount++;
if(clickCount == 3) {
tripleClick(); //your tripleClick method
clickCount=0;
tripleClick = false;
leftClick = false;
}
} else if(leftClick) {
System.out.println("single click.");
leftClick = false;
}
}
});
timer.setRepeats(false);
timer.start();
if(evt.getID()==MouseEvent.MOUSE_RELEASED) timer.stop();
}
}
public static void main(String[] argv) throws Exception {
JTextField component = new JTextField();
component.addMouseListener(new TestMouseListener());
JFrame f = new JFrame();
f.add(component);
f.setSize(300, 300);
f.setVisible(true);
component.addMouseListener(new TestMouseListener());
}
}

Categories