在 Java 中捕获(捕获)窗口中的鼠标光标

发布于 2024-08-25 11:14:35 字数 4668 浏览 2 评论 0原文

我正在寻找一种方法,在鼠标进入窗口后捕获或捕获该窗口中的鼠标,就像鼠标被捕获在虚拟机窗口中一样,直到用户按 CTRL+ALT+DEL 或以其他方式释放鼠标。我如何在 Java 中实现这一点?全屏显示不是一个选择。

编辑:

这里有一些 SSCCE 供您参考。此代码会将您的鼠标困在窗口中。要退出,您只需在生成的框架内并直接移动到关闭按钮即可。如果您注意到,当鼠标试图离开时,它会自动返回到 (0,0)。我需要知道的是如何让它返回到它退出的坐标。我尝试用 getX() 和 getY() 代替 (0,0),但机器人不会将鼠标返回那里(我认为响应时间很慢)。我还让机器人将鼠标移回到 crosshair.x 和 crosshair.y,但是如果用户在正确的时刻单击,这(以及其他)仍然允许鼠标逃脱。有什么想法吗?

主类:

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferStrategy;
import java.awt.image.MemoryImageSource;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import javax.swing.JFrame;

public class Game extends JFrame implements MouseMotionListener, MouseListener{

    private int windowWidth = 640;
    private int windowHeight = 480;
        private Crosshair crosshair;

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

    public Game() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(windowWidth, windowHeight);
        this.setResizable(false);
        this.setLocation(0,0);
        this.setVisible(true);

        this.createBufferStrategy(2);
                addMouseMotionListener(this);
                addMouseListener(this);
        initGame();

        while(true) {
            long start = System.currentTimeMillis();
            gameLoop();
            while(System.currentTimeMillis()-start < 5) {
                            //empty while loop
            }
        }
    }

    private void initGame() {
            hideCursor();
            crosshair = new Crosshair (windowWidth/2, windowHeight/2);
    }

        private void gameLoop() {
            //game logic
            drawFrame();
        }

        private void drawFrame() {

            BufferStrategy bf = this.getBufferStrategy();
            Graphics g = (Graphics)bf.getDrawGraphics();
            try {
                g = bf.getDrawGraphics();
                Color darkBlue = new Color(0x010040);
                g.setColor(darkBlue);
                g.fillRect(0, 0, windowWidth, windowHeight);
                drawCrossHair(g);
            } finally {
                g.dispose();
            }
            bf.show();
            Toolkit.getDefaultToolkit().sync();
        }

        private void drawCrossHair(Graphics g){
            Color yellow = new Color (0xEDFF62);
            g.setColor(yellow);
            g.drawOval(crosshair.x, crosshair.y, 40, 40);

            g.fillArc(crosshair.x + 10, crosshair.y + 21 , 20, 20, -45, -90);
            g.fillArc(crosshair.x - 1, crosshair.y + 10, 20, 20, -135, -90);
            g.fillArc(crosshair.x + 10, crosshair.y - 1, 20, 20, -225, -90);
            g.fillArc(crosshair.x + 21, crosshair.y + 10, 20, 20, -315, -90);
        }

        @Override
        public void mouseDragged(MouseEvent e) {
        //empty method
        }

        @Override
        public void mouseMoved(MouseEvent e) {
        crosshair.x = e.getX();
        crosshair.y = e.getY();
        }

        private void hideCursor() {
            int[] pixels = new int[16 * 16];
            Image image = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(16, 16, pixels, 0, 16));
            Cursor transparentCursor = Toolkit.getDefaultToolkit().createCustomCursor(image, new Point(0, 0), "invisiblecursor");
            getContentPane().setCursor(transparentCursor);
    }

        public void mouseExited(MouseEvent e) {
            System.out.println("Event: " + e);
            try {
                Robot robot = new Robot();
                robot.mouseMove(0, 0);// When I use (getX(),getY()) instead of (0,0) the robot will not move the mouse at all even though getX() and getY() are the coordinates I want the mouse to be moved to.  Also the mouse can still escape, even when crosshair.x and crosshair.y are used as the coordinates.  It seems that robot is too slow.
            }
            catch (AWTException ex) {
                ex.printStackTrace();
            }
        }

        public void mouseEntered(MouseEvent e){
        }

        public void mousePressed(MouseEvent e) {
        }

        public void mouseReleased(MouseEvent e) {
        }

        public void mouseClicked(MouseEvent e) {
        }
}

另一类:

public class Crosshair{
        public int x;
    public int y;
    public Crosshair(int x, int y) {
        this.x = x;
        this.y = y;
        }
}

I am looking for a way to capture or trap the mouse in a window after it has entered that window much like a mouse is trapped in a virtual machine window until a user presses CTRL+ALT+DEL or release the mouse in some other manner. How do I make this happen in Java? Going full screen is not an option.

EDIT:

Here is some SSCCE for ya. This code will trap your mouse in the window. To get out you just have to within the generated frame and move directly to the close button. If you will notice when your mouse tries to leave it automatically goes back to (0,0). What I need to know is how do I get it to go back to the coordinates where it exited from. I tried getX() and getY() in place of (0,0) but the robot does not return the mouse there (I think the response time is to slow). I also have had the robot move the mouse back to crosshair.x and crosshair.y but this (as well as the others) still allows the mouse to escape if the user clicks at the right moment. Any thoughts?

Main Class:

import java.awt.AWTException;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferStrategy;
import java.awt.image.MemoryImageSource;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import javax.swing.JFrame;

public class Game extends JFrame implements MouseMotionListener, MouseListener{

    private int windowWidth = 640;
    private int windowHeight = 480;
        private Crosshair crosshair;

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

    public Game() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(windowWidth, windowHeight);
        this.setResizable(false);
        this.setLocation(0,0);
        this.setVisible(true);

        this.createBufferStrategy(2);
                addMouseMotionListener(this);
                addMouseListener(this);
        initGame();

        while(true) {
            long start = System.currentTimeMillis();
            gameLoop();
            while(System.currentTimeMillis()-start < 5) {
                            //empty while loop
            }
        }
    }

    private void initGame() {
            hideCursor();
            crosshair = new Crosshair (windowWidth/2, windowHeight/2);
    }

        private void gameLoop() {
            //game logic
            drawFrame();
        }

        private void drawFrame() {

            BufferStrategy bf = this.getBufferStrategy();
            Graphics g = (Graphics)bf.getDrawGraphics();
            try {
                g = bf.getDrawGraphics();
                Color darkBlue = new Color(0x010040);
                g.setColor(darkBlue);
                g.fillRect(0, 0, windowWidth, windowHeight);
                drawCrossHair(g);
            } finally {
                g.dispose();
            }
            bf.show();
            Toolkit.getDefaultToolkit().sync();
        }

        private void drawCrossHair(Graphics g){
            Color yellow = new Color (0xEDFF62);
            g.setColor(yellow);
            g.drawOval(crosshair.x, crosshair.y, 40, 40);

            g.fillArc(crosshair.x + 10, crosshair.y + 21 , 20, 20, -45, -90);
            g.fillArc(crosshair.x - 1, crosshair.y + 10, 20, 20, -135, -90);
            g.fillArc(crosshair.x + 10, crosshair.y - 1, 20, 20, -225, -90);
            g.fillArc(crosshair.x + 21, crosshair.y + 10, 20, 20, -315, -90);
        }

        @Override
        public void mouseDragged(MouseEvent e) {
        //empty method
        }

        @Override
        public void mouseMoved(MouseEvent e) {
        crosshair.x = e.getX();
        crosshair.y = e.getY();
        }

        private void hideCursor() {
            int[] pixels = new int[16 * 16];
            Image image = Toolkit.getDefaultToolkit().createImage(new MemoryImageSource(16, 16, pixels, 0, 16));
            Cursor transparentCursor = Toolkit.getDefaultToolkit().createCustomCursor(image, new Point(0, 0), "invisiblecursor");
            getContentPane().setCursor(transparentCursor);
    }

        public void mouseExited(MouseEvent e) {
            System.out.println("Event: " + e);
            try {
                Robot robot = new Robot();
                robot.mouseMove(0, 0);// When I use (getX(),getY()) instead of (0,0) the robot will not move the mouse at all even though getX() and getY() are the coordinates I want the mouse to be moved to.  Also the mouse can still escape, even when crosshair.x and crosshair.y are used as the coordinates.  It seems that robot is too slow.
            }
            catch (AWTException ex) {
                ex.printStackTrace();
            }
        }

        public void mouseEntered(MouseEvent e){
        }

        public void mousePressed(MouseEvent e) {
        }

        public void mouseReleased(MouseEvent e) {
        }

        public void mouseClicked(MouseEvent e) {
        }
}

Another Class:

public class Crosshair{
        public int x;
    public int y;
    public Crosshair(int x, int y) {
        this.x = x;
        this.y = y;
        }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

诠释孤独 2024-09-01 11:14:35

我想你可以使用 全局事件监听器 来监听鼠标输入该帧的事件。然后,在鼠标退出事件中,我想您可以使用机器人在鼠标离开框架后重置鼠标的位置。

I guess you could use a Global Event Listener to listen for mouse entered events for the frame. Then on a mouse exited event I suppose you could use the Robot to reset the location of the mouse once it leaves the frame.

泛泛之交 2024-09-01 11:14:35

好吧,我不想假装自己是游戏开发人员,但链接中提供的代码对于简单的“乒乓球游戏”来说非常糟糕(据我所知)。我复制了代码并运行它,以便球可以弹跳。

在我的计算机上,CPU 利用率为 50%,因为无限 while 循环浪费了 CPU 时间来提供球运动的动画。使用休眠 5 毫秒的线程而不是占用 CPU 5 毫秒的简单更改会导致 CPU 使用率下降到大约 18%。

然后我更改了代码以在 Swing 面板上制作球动画。代码更容易编写,CPU 使用率下降到 1%,并且球动画速度更快。

这是我的最终版本。您应该能够通过不将面板添加到框架然后再次调用 drawFrame() 方法来切换回使用缓冲策略。

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;

import javax.swing.*;

public class Game3 extends JFrame {

    /**
     * @author Georgi Khomeriki
     */

    private Ball ball;

    // added this
    private JPanel gamePanel;

    private int windowWidth = 800;
    private int windowHeight = 600;


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

    public Game3() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(windowWidth, windowHeight);
        this.setResizable(false);
        this.setLocation(100, 100);
        this.setVisible(true);

        this.createBufferStrategy(2);

        initGame3();
/*
        while(true) {
            long start = System.currentTimeMillis();
            gameLoop();
            while(System.currentTimeMillis()-start < 5) {
                 //do nothing
            }
        }
*/

        Thread thread = new Thread(new Runnable()
        {
            public void run()
            {
                while(true)
                {
                    gameLoop();
                    try { Thread.sleep(5); }
                    catch(Exception e) {}
                }
            }
        });
        thread.start();

    }

    private void initGame3() {
        // all you're game variables should be initialized here
        ball = new Ball(windowWidth/2, windowHeight/2, 5, 5);

        // added these lines

        gamePanel = new GamePanel();
        gamePanel.setBackground(Color.BLACK);
        add(gamePanel);
    }

    private void gameLoop() {
        // your game logic goes here

// move the ball
    ball.x = ball.x + ball.dx;
    ball.y = ball.y + ball.dy;

    // change the direction of the ball if it hits a wall
    if(ball.x <= 0 || ball.x >= windowWidth-40)
        ball.dx = -ball.dx;
    if(ball.y <= 0 || ball.y >= windowHeight-40)
        ball.dy = -ball.dy;


        // changed to following to use Swing instead of buffer strategy
//      drawFrame();
        gamePanel.repaint();
    }

    private void drawFrame() {
        // code for the drawing goes here
        BufferStrategy bf = this.getBufferStrategy();
        Graphics g = null;

        try {
            g = bf.getDrawGraphics();

            // clear the back buffer (just draw a big black rectangle over it)
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, windowWidth, windowHeight);

drawBall(g);


        } finally {
            // It is best to dispose() a Graphics object when done with it.
            g.dispose();
        }

        // Shows the contents of the backbuffer on the screen.
        bf.show();

        //Tell the System to do the Drawing now, otherwise it can take a few extra ms until
        //Drawing is done which looks very jerky
        Toolkit.getDefaultToolkit().sync();
    }

    private void drawBall(Graphics g) {

        g.setColor(Color.GREEN);
        g.fillOval(ball.x, ball.y, 40, 40);
    }

    // added this

    class GamePanel extends JPanel
    {
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            drawBall(g);
        }
    }


    class Ball {

        public int x;
        public int y;
        public int dx;
        public int dy;

        public Ball(int x, int y, int dx, int dy) {
            this.x = x;
            this.y = y;
            this.dx = dx;
            this.dy = dy;
        }
    }



}

Well, I don't pretend to be a game developer but the code presented in the link is terrible (from what I can tell) for a simple "pong game". I copied the code and got it running so that the ball bounces around.

On my computer the CPU is 50% because of the infinite while loop that wastes CPU time to provide the animation for ball movement. The simple change to use a Thread that sleeps for 5ms rather than hog the CPU for 5ms, causes the CPU usage to drop down to about 18%.

I then changed the code to do the ball animation on a Swing panel. The code is easier to write and the CPU usage dropped to 1% and the ball animation was much faster.

Here is my final version. You should be able to swap back to using the buffered strategy by not adding the panel to the frame and then by invoking the drawFrame() method again.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;

import javax.swing.*;

public class Game3 extends JFrame {

    /**
     * @author Georgi Khomeriki
     */

    private Ball ball;

    // added this
    private JPanel gamePanel;

    private int windowWidth = 800;
    private int windowHeight = 600;


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

    public Game3() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setSize(windowWidth, windowHeight);
        this.setResizable(false);
        this.setLocation(100, 100);
        this.setVisible(true);

        this.createBufferStrategy(2);

        initGame3();
/*
        while(true) {
            long start = System.currentTimeMillis();
            gameLoop();
            while(System.currentTimeMillis()-start < 5) {
                 //do nothing
            }
        }
*/

        Thread thread = new Thread(new Runnable()
        {
            public void run()
            {
                while(true)
                {
                    gameLoop();
                    try { Thread.sleep(5); }
                    catch(Exception e) {}
                }
            }
        });
        thread.start();

    }

    private void initGame3() {
        // all you're game variables should be initialized here
        ball = new Ball(windowWidth/2, windowHeight/2, 5, 5);

        // added these lines

        gamePanel = new GamePanel();
        gamePanel.setBackground(Color.BLACK);
        add(gamePanel);
    }

    private void gameLoop() {
        // your game logic goes here

// move the ball
    ball.x = ball.x + ball.dx;
    ball.y = ball.y + ball.dy;

    // change the direction of the ball if it hits a wall
    if(ball.x <= 0 || ball.x >= windowWidth-40)
        ball.dx = -ball.dx;
    if(ball.y <= 0 || ball.y >= windowHeight-40)
        ball.dy = -ball.dy;


        // changed to following to use Swing instead of buffer strategy
//      drawFrame();
        gamePanel.repaint();
    }

    private void drawFrame() {
        // code for the drawing goes here
        BufferStrategy bf = this.getBufferStrategy();
        Graphics g = null;

        try {
            g = bf.getDrawGraphics();

            // clear the back buffer (just draw a big black rectangle over it)
            g.setColor(Color.BLACK);
            g.fillRect(0, 0, windowWidth, windowHeight);

drawBall(g);


        } finally {
            // It is best to dispose() a Graphics object when done with it.
            g.dispose();
        }

        // Shows the contents of the backbuffer on the screen.
        bf.show();

        //Tell the System to do the Drawing now, otherwise it can take a few extra ms until
        //Drawing is done which looks very jerky
        Toolkit.getDefaultToolkit().sync();
    }

    private void drawBall(Graphics g) {

        g.setColor(Color.GREEN);
        g.fillOval(ball.x, ball.y, 40, 40);
    }

    // added this

    class GamePanel extends JPanel
    {
        protected void paintComponent(Graphics g)
        {
            super.paintComponent(g);
            drawBall(g);
        }
    }


    class Ball {

        public int x;
        public int y;
        public int dx;
        public int dy;

        public Ball(int x, int y, int dx, int dy) {
            this.x = x;
            this.y = y;
            this.dx = dx;
            this.dy = dy;
        }
    }



}
时光磨忆 2024-09-01 11:14:35

正如 camickr 提到的,您可以使用机器人来完成此操作。人们通常会建议不要这样做,但这里有一个非常好的机器人入门知识可以帮助您入门:

http://www.developer.com/java/other/article.php/2212401/Introduction-to-the-Java-Robot -Java中的类.htm

As camickr mentions, you can do this using the Robot. It's generally something that people would recommend against, but here's a pretty good Robot primer to get you started:

http://www.developer.com/java/other/article.php/2212401/Introduction-to-the-Java-Robot-Class-in-Java.htm

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文