java swing 如何获取鼠标的实时位置?

How to get the live location of mouse in java swing?

我正在尝试创建一个简单的井字游戏,我想在鼠标所在的方块上显示高亮显示。我在 java.awt.Canvas 上画了游戏,目前,我尝试了这些失败的方法:

顺便说一句,这是我的代码:

Class 用于覆盖 MouseAdaper 的方法:

public class MouseInput extends MouseAdapter {

    private final Game game;
    private final int i;
    private final int j;

    public MouseInput(Game game, JPanel panel){
        this.game = game;
        i = panel.getY() / 64;
        j = panel.getX() / 64;
    }
    @Override
    public void mouseEntered(MouseEvent e) {
        game.mouseEntered(i, j);
    }

    @Override
    public void mouseExited(MouseEvent e) {
        game.mouseExited(i, j);
    }

    @Override
    public void mouseClicked(MouseEvent e){
        game.mouseClicked(i, j);
    }
}
游戏中

JPanels 并向其添加 MouseListener

public class Game extends Canvas implements Runnable {
    private boolean isRunning = false;
    private Thread thread;
    private final JPanel[][] panels = new JPanel[3][3];

    public static void main(String[] args) {

        Game game = new Game();
        game.setPreferredSize(new Dimension(192, 192));

        JFrame frame = new JFrame();
        frame.add(game);
        frame.setResizable(false);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        game.start();
    }

    private void start(){
        if(isRunning){
            return;
        }

        isRunning = true;
        thread = new Thread(this);
        thread.start();
    }

    private void stop(){
        if(!isRunning){
            return;
        }

        isRunning = false;
        try {
            thread.join();
        } catch (InterruptedException ignored) {}
        System.exit(0);
    }

    @Override
    public void run(){
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++){
                JPanel p  = new JPanel();
                p.setPreferredSize(new Dimension(64, 64));
                p.setLocation(j * 64, i * 64);
                p.addMouseListener(new MouseInput(this, p));
                panels[i][j] = p;
            }
        }
    }
}

Swing 不是线程安全的,而是单线程的。您不应该更新 UI 或更新 UI 依赖于事件调度线程上下文之外的内容。

在您的情况下,面板实际上并未附加到任何东西(即添加到容器),因此无法响应任何事件。

您还应该花时间学习一些布局管理基础知识。

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;

public class Test {
    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();

                JPanel board = new JPanel(new GridLayout(3, 3));
                for (int index = 0; index < 9; index++) {
                    board.add(new GridPane());
                }

                frame.add(board);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class GridPane extends JPanel {

        private MouseListener mouseHandler;

        public GridPane() {
            setBorder(new LineBorder(Color.BLACK));
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(50, 50);
        }

        @Override
        public void addNotify() {
            super.addNotify(); 

            if (mouseHandler != null) {
                removeMouseListener(mouseHandler);
            }

            mouseHandler = new MouseAdapter() {
                @Override
                public void mouseEntered(MouseEvent e) {
                    setBackground(Color.RED);
                }

                @Override
                public void mouseExited(MouseEvent e) {
                    setBackground(null);
                }
            };

            addMouseListener(mouseHandler);
        }

        @Override
        public void removeNotify() {
            super.removeNotify();
            if (mouseHandler != null) {
                removeMouseListener(mouseHandler);
            }
        }


    }
}

而不是试图让一个听众尝试更新游戏模型。将游戏引用传递给每个面板并让它完成这项工作。通过这种方式,您可以将“标识符”传递给每个可以传递回游戏的单元格,以便它可以做出一些需要的决定。