2010-03-20 115 views
3

我正在尋找一種方法來在窗口中捕獲或捕獲鼠標後進入該窗口,就像鼠標被困在虛擬機窗口中一樣,直到用戶按下CTRL + ALT + DEL或以其他方式釋放鼠標。我如何在Java中做到這一點?全屏顯示不是一種選擇。捕獲(捕獲)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; 
     } 
} 
+1

這樣做會*如果我是用戶真的很煩我。 – 2010-03-20 04:01:06

+0

我知道你在說什麼,但這是必要的,因爲我設置了Hotas Cougar(一個操縱桿)來模擬鼠標移動,並且我寫了我的代碼,因此十字線由鼠標移動控制。我打算放入一些功能,允許窗口以用戶友好的方式「釋放」鼠標。 – ubiquibacon 2010-03-20 05:06:05

回答

4

我想你可以使用一個Global Event Listener爲偵聽鼠標進入該框架的事件。然後,在鼠標退出的事件中,我想您可以使用機器人在鼠標離開框架後重置鼠標的位置。

+0

好的camick,我讀了你的博客(非常好),我在mouseExited事件中設置了一個機器人。機器人將鼠標移回一組絕對座標,但我希望機器人將鼠標移回到退出的EXACT位置。我使用getX()和getY(),但機器人不會將鼠標移回那裏(我認爲響應時間太慢)。我也使用了我的十字準線(crosshair.x和十字準線)的座標。y),但即使如此,如果用戶在正確的時間點擊,鼠標仍然可以逃脫。有什麼想法嗎? – ubiquibacon 2010-03-20 08:44:22

+0

你應該使用event.getX()和event.getY()。此外,這些點與框架相關,而機器人需要使用相對於屏幕的位置。您可以使用SwingUtilities類中的方法來進行轉換。而且您可能需要調整這些點,因爲mouseExited事件不一定會在幀邊界處生成點,具體取決於拖動鼠標的速度。 – camickr 2010-03-20 19:30:52

+0

關於鼠標轉義和點擊另一個組件,我不知道如何解決這個問題(雖然我不能複製它,我想我太慢了)。無論如何,當我運行你的演示,我的CPU跳到50%,因爲你無限的while循環。這顯然不是構建遊戲的方式。也許如果CPU不被佔用,機器人會更快響應。遊戲循環通常可以通過Swing Timer來控制,因此您不會佔用CPU。我也不確定你從哪裏得到你的代碼。 Swing是雙緩衝的,所以不需要使用BufferStrategy。 – camickr 2010-03-20 19:36:36

2

好吧,我不假裝是一個遊戲開發者,但代碼中的鏈接介紹的是可怕的(從我可以告訴的)一個簡單的「乒乓球比賽」。我複製了代碼並使其運行,以便球彈跳。

在我的電腦上,CPU是50%,因爲無限的while循環浪費了CPU時間來提供球的運動動畫。使用一個睡眠時間爲5ms的線程的簡單改變,而不是使CPU持續5ms,導致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; 
     } 
    } 



} 
+0

我還有其他一些東西可以跟上,但我會在本週晚些時候看definitley。謝謝! – ubiquibacon 2010-03-21 21:50:18