organizara
organizara

Reputation: 1

Java Swing: 'java.awt.AWTEventMulticaster.mouseMoved' error

I have been trying to create a 'catch me if you can' game: when I start it, it randomly chooses where to allocate a 'click me' button. I am not supposed to be able to click the button, the text should be re-assigned to another button before I am able to do that.

It works for a while but then it throws the following error: "java.awt.AWTEventMulticaster.mouseMoved".

I have been trying to fix the problem with removeListener() method but I don't seem to be able to find a solution. Any comments?

Here's my code:

import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.lang.*;

public class Game extends JFrame {
    //Panels
    private JPanel mainPanel = new JPanel();
    // Buttons
    private JButton[] buttons = new JButton[9];
    private JButton theChosenButton = new JButton();
    // other
    private int random = 0; 

    public Game() {
        this.setTitle("Catch me if you can");
        mainPanel.setLayout(new GridLayout(3, 3));

        // creates buttons
        for(int i = 0; i < 9 ; i++) {
            buttons[i] = new JButton();
            mainPanel.add(buttons[i]);
        }

        // Add everything to frame
        this.getContentPane().add(mainPanel);
        this.setSize(400, 400);
        this.setVisible(true);
    }

    // generates random number between 1 and 9 to be used 
    public int clickMeGenerator(){
        random = (int) Math.floor(Math.random() * 9);
        return random;
    }

    // randomly assigns clickMeGenerator to a button
    // add mouseMoved listener to the chosen button
    public void assign(){
        int randomButton = this.clickMeGenerator();
        theChosenButton = buttons[randomButton];
        theChosenButton.addMouseMotionListener(new MouseHover());
        theChosenButton.setText("Click me");    
    }
    public void removeListener() {
            theChosenButton.removeMouseMotionListener(new MouseHover());
        //}
    }

    // inner class
    class MouseHover implements MouseMotionListener {
        public void mouseMoved(MouseEvent e) {
            theChosenButton.setText("");
            Game.this.assign();

        }

        public void mouseDragged(MouseEvent e) {

        }
    }

} // end of class

Test class:

public class GameTest {
    public static void main (String args[]) {
        Game myGame = new Game();
        myGame.assign();
    }
}

Thank you so much for your help!

Upvotes: 0

Views: 529

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347284

Just for clarity, the "actual" error is ...

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
    at java.desktop/java.awt.AWTEventMulticaster.mouseMoved(AWTEventMulticaster.java:337)
    at java.desktop/java.awt.AWTEventMulticaster.mouseMoved(AWTEventMulticaster.java:337)

So looking through the code...

  public void assign() {
    int randomButton = this.clickMeGenerator();
    theChosenButton = buttons[randomButton];
    theChosenButton.addMouseMotionListener(new MouseHover());
    theChosenButton.setText("Click me");
  }

You are repeatedly add a new MouseMotionListener to you buttons, over and over again, and...

  public void removeListener() {
    theChosenButton.removeMouseMotionListener(new MouseHover());
    //}
  }

is pointless, as you're trying to remove a new instance of MouseHover from the button, but it will never have been applied in the first place.

The first thing I would do is create an instance of MouseHover as an instance field in Game

 private MouseHover mouseHover = new MouseHover();

and use it when calling addMouseMotionListener and removeMouseMotionListener.

I would then, remove the listener from the "currently" active button before adding it to the next one.

Personally, I would do this in the assign method

public void assign() {
  int randomButton = this.clickMeGenerator();
  if (theChosenButton != null) {
    theChosenButton.removeMouseMotionListener(mouseHover);
  }
  theChosenButton = buttons[randomButton];
  theChosenButton.addMouseMotionListener(mouseHover);
  theChosenButton.setText("Click me");
}

I would also ensure that assign is called from within the Event Dispatching Thread when the class is first created, as the UI has been realised by the end of the constructor of Game, meaning the first call to assign is outside of the context of the EDT, which is not recommended.

public static void main(String args[]) {
  EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
      Game myGame = new Game();
      myGame.assign();
    }
  });
}

Upvotes: 1

Related Questions