You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Swing中mouseMoved快速移鼠时对象无法追踪鼠标的解决方法

问题分析

  1. 判断逻辑错误:你的代码用||(逻辑或)判断鼠标是否在方块范围内,这会导致只要鼠标X坐标在方块X区间或者Y坐标在方块Y区间就触发跟随,完全不符合“鼠标移至对象上方”的需求,应该用&&(逻辑与),只有X和Y同时落在方块范围内才判定鼠标在方块上。

  2. 快速移动的事件遗漏:Swing的mouseMoved事件触发频率有限,快速移动鼠标时,鼠标位置可能直接跳过方块区域,导致后续mouseMoved事件中鼠标不在方块内,方块停止跟随。如果需要鼠标悬停在方块上时,即使快速移动也不脱离,需要优化跟随逻辑。

解决方案

方案1:修复基础判断逻辑

将鼠标位置的判断条件从||改为&&,确保只有鼠标完全处于方块范围内才触发跟随:

@Override
public void mouseMoved(MouseEvent e) {
    // 转换为相对于画布的坐标
    int cursorX = e.getX() - barX;
    int cursorY = e.getY() - barY;
    // 修复为逻辑与判断
    if (cursorX > startX && cursorX < startX + sizeBox && cursorY > startY && cursorY < startY + sizeBox) {
        startX = cursorX - sizeBox / 2;
        startY = cursorY - sizeBox / 2;
    }
    repaint();
}

方案2:添加跟随状态标记(解决快速脱离问题)

如果希望鼠标悬停在方块上后,即使短暂移出方块也能持续跟随,直到明确移出范围,可以添加状态变量跟踪跟随状态:

  1. 添加状态变量:
private boolean isFollowing = false;
  1. 修改mouseMoved逻辑:
@Override
public void mouseMoved(MouseEvent e) {
    int cursorX = e.getX() - barX;
    int cursorY = e.getY() - barY;
    boolean isMouseOver = cursorX > startX && cursorX < startX + sizeBox && cursorY > startY && cursorY < startY + sizeBox;

    if (isMouseOver) {
        isFollowing = true;
    }
    // 处于跟随状态时持续更新位置,直到鼠标完全移出方块
    if (isFollowing) {
        startX = cursorX - sizeBox / 2;
        startY = cursorY - sizeBox / 2;
        if (!isMouseOver) {
            isFollowing = false;
        }
    }
    repaint();
}

方案3:使用可靠的坐标转换工具

手动减去barX和barY的方式不够稳定,建议用SwingUtilities.convertPoint将鼠标坐标转换为相对于画布的坐标:

@Override
public void mouseMoved(MouseEvent e) {
    Point canvasPoint = SwingUtilities.convertPoint(Test.this, e.getPoint(), canvas);
    int cursorX = canvasPoint.x;
    int cursorY = canvasPoint.y;

    boolean isMouseOver = cursorX >= startX && cursorX <= startX + sizeBox 
                        && cursorY >= startY && cursorY <= startY + sizeBox;

    if (isMouseOver) {
        isFollowing = true;
    }
    if (isFollowing) {
        startX = cursorX - sizeBox / 2;
        startY = cursorY - sizeBox / 2;
        if (!isMouseOver) {
            isFollowing = false;
        }
    }
    repaint();
}

同时可以简化初始位置:

private int startX = 100;
private int startY = 100;

完整修改后的代码

import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle;

public class Test extends JFrame {
    DrawWorld canvas;
    private int startX = 100;
    private int startY = 100;
    private int sizeBox = 30;
    private Color colorBox = Color.GREEN;
    private boolean isFollowing = false;

    public Test() {
        canvas = new DrawWorld();
        setPreferredSize(new Dimension(1366, 768));
        setLayout(new FlowLayout());
        setContentPane(canvas);

        addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                Point canvasPoint = SwingUtilities.convertPoint(Test.this, e.getPoint(), canvas);
                int cursorX = canvasPoint.x;
                int cursorY = canvasPoint.y;

                boolean isMouseOver = cursorX >= startX && cursorX <= startX + sizeBox 
                                    && cursorY >= startY && cursorY <= startY + sizeBox;

                if (isMouseOver) {
                    isFollowing = true;
                }

                if (isFollowing) {
                    startX = cursorX - sizeBox / 2;
                    startY = cursorY - sizeBox / 2;
                    if (!isMouseOver) {
                        isFollowing = false;
                    }
                }
                repaint();
            }
        });

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Game");
        pack();
        setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(Test::new);
    }

    private class DrawWorld extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g;
            Shape square = new Rectangle(startX, startY, sizeBox, sizeBox);
            g2d.setColor(colorBox);
            g2d.fill(square);
        }
    }
}

内容的提问来源于stack exchange,提问作者kenya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:44:55