Java Swing: ошибка «java.awt.AWTEventMulticaster.mouseMoved» - PullRequest
0 голосов
/ 13 декабря 2018

Я пытался создать игру «поймай меня, если сможешь»: когда я ее запускаю, она случайным образом выбирает место для кнопки «кликни мне».Я не должен нажимать кнопку, текст должен быть переназначен другой кнопке, прежде чем я смогу это сделать.

Это работает некоторое время, но затем выдает следующую ошибку: "java.awt.AWTEventMulticaster.mouseMoved».

Я пытался исправить проблему с помощью метода removeListener (), но мне не удалось найти решение.Любые комментарии?

Вот мой код:

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

Тестовый класс:

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

Большое спасибо за вашу помощь!

1 Ответ

0 голосов
/ 13 декабря 2018

Просто для ясности, "фактическая" ошибка ...

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)

Итак, просматривая код ...

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

Вы неоднократно добавляете новый MouseMotionListener для вас кнопки, снова и снова, и ...

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

бессмысленно, так как вы пытаетесь удалить новый экземпляр MouseHover с кнопки, но он никогда не будетприменяется в первую очередь.

Первое, что я хотел бы сделать, это создать экземпляр MouseHover в качестве поля экземпляра в Game

 private MouseHover mouseHover = new MouseHover();

и использовать его при вызове addMouseMotionListener и removeMouseMotionListener.

Затем я бы удалил слушателя из «текущей» активной кнопки перед добавлением его к следующей.

Лично я бы сделал это в 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");
}

Я бы также гарантировал, что assign вызывается из потока диспетчеризации событий при первом создании класса, поскольку пользовательский интерфейс был реализован концом конструктора GameЭто означает, что первый вызов assign находится вне контекста EDT, что не рекомендуется.

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