2012-05-11 51 views
1

我在嘗試使用Java創建遊戲時遇到問題。我試圖將一個MouseListener附加到我的畫布上,但是,當我單擊畫布時,沒有任何反應。我想我可能會將MouseListener附加到錯誤的東西上,但我不知道該如何附加它。我試圖將它附加到JFrame和畫布上。這裏是我的代碼:Canvas中的MouseListener無法正常工作

import java.awt.*; 
import java.awt.event.*; 
import java.util.ArrayList; 

import java.io.*; 

import javax.imageio.ImageIO; 
import javax.swing.*; 
import java.util.Random; 

public class Gravity extends Canvas { 

    public static final int screenw = 1024; 
    public static final int screenh = 768; 

    public static Random gen = new Random(); 

    public static Boolean started = false; 

    public static int[] starx = new int[100]; 
    public static int[] stary = new int[100]; 
    public static Color[] starc = new Color[100]; 

    public static JFrame frame; 
    public static Gravity canvas; 
    public static Image buffer; 
    public static Graphics bg; 

    public static int[] xh = new int[1000]; 
    public static int[] yh = new int[1000]; 

    public static int i = 0; 

    public static Image title; 

    public static ArrayList<Integer> ptx = new ArrayList<Integer>(); 
    public static ArrayList<Integer> pty = new ArrayList<Integer>(); 
    double x = 100; 
    double y = 100; 

    public Gravity(){ 
    } 

    public void paint (Graphics g) { 
     frame.addMouseListener(new MouseListener(){ 
      public void mouseClicked(MouseEvent e){ 
       started = true; 
       System.out.println("Mouse was clicked"); 
      } 

      public void mouseEntered(MouseEvent arg0) {} 
      public void mouseExited(MouseEvent arg0) {} 
      public void mousePressed(MouseEvent arg0) {} 
      public void mouseReleased(MouseEvent arg0) {} 
     }); 


     buffer = createImage(screenw, screenh); 
     bg = buffer.getGraphics(); 

     int w = getWidth(); 
     int h = getHeight(); 

     double px = getWidth()/2; 
     double py = getHeight()/2; 

     bg.setColor(Color.BLACK); 
     bg.fillRect(0, 0, w, h); //black background 

     for (int j=0; j < 100; j++){ //make stars 
      starx[j] = gen.nextInt(w); 
      stary[j] = gen.nextInt(h); 
      starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156); 
      bg.setColor(starc[j]); 
      bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2); 
      bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]); 
     } 

     try { 
      title = ImageIO.read(new ByteArrayInputStream(Base64.decode(""))); //I have omitted the Base64 code for the image for my title screen 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     bg.drawImage(title, 100, 100, null); 
     g.drawImage(buffer, 0, 0, null); 

     while (!started){ 
      try { 
       Thread.sleep(50); 
      } catch (InterruptedException e1) { 
       e1.printStackTrace(); 
      } 
     } 

     double xvel = -15; 
     double yvel = 10; 

     for (int j=0; j < 100; j++){ //store stars 
      starx[j] = gen.nextInt(w); 
      stary[j] = gen.nextInt(h); 
      starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156); 
     } 

     Image test = createImage(200,200); 
     Graphics testg = test.getGraphics(); 
     testg.drawLine(50,50,150,150); 

     while(true){ 
      g.drawImage(buffer, 0,0, null); 
      try { 
       Thread.sleep(33); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 

      bg.setColor(Color.BLACK); 
      bg.fillRect(0, 0, w, h); //black background 


      for (int j=0; j < 100; j++){ //draw stars 
       bg.setColor(starc[j]); 
       bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2); 
       bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]); 
      } 

      bg.setColor(Color.BLUE); 

      if (i > 0){ 
       for (int z=0; z < i-1; z++){ 
        bg.drawLine(ptx.get(z), pty.get(z), ptx.get(z+1), pty.get(z+1)); 
       } 
      } 

      bg.setColor(Color.CYAN); 
      bg.fillOval((int)px, (int)py, 25, 25); //planet 

      bg.setColor(Color.RED); 
      bg.fillRect((int)(x-5),(int)(y-5),10,10); //ship 

      double fg = (5*50000)/(Math.pow(dist(x,y,px,py),2)); 

      double m = (y-py)/(x-px); 
      double ms = Math.sqrt(Math.abs(m)); 
      if (m < 0) ms = -ms; 

      double xchg = fg; 
      double ychg = fg*ms; 

      if (x > px){ 
       xchg = -xchg; 
       ychg = -ychg; 
      } 

      xvel += xchg; 
      yvel += ychg; 

      x += xvel; 
      y += yvel; 

      ptx.add((int)x); 
      pty.add((int)y); 

      i++; 
     } 
    } 

    public static void main(String[] args){ 

     canvas = new Gravity(); 
     frame = new JFrame(); 
     frame.setSize(screenw, screenh); 
     frame.setResizable(false); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.getContentPane().add(canvas); 

     frame.setVisible(true); 
    } 


    public static double dist(double x1, double y1, double x2, double y2){ 
     double x = x2-x1; 
     double y = y2-y1; 
     return Math.sqrt((x*x)+(y*y)); 
    } 
} 
+0

感謝大家回答。我不明白'paint()'和Canvas的基本概念,即'paint()'如何被重複執行多次。我將嘗試將其更改爲使用JPanel而不是Canvas。 – bdr9

回答

3

的常用技巧,以點形式:

  1. 不要混合使用AWT(例如Canvas)與Swing(例如JFrame)組件。代替Canvas,請使用JPanel並覆蓋paintComponent(Graphics)而不是paint(Graphics)
  2. 請勿在EDT上撥打Thread.sleep(n)。請使用基於Swing的Timer來調用repaint()
  3. 不要對paint方法執行長時間運行操作,尤其是啓動無限循環!即使只是在屏幕尺寸發生變化的情況下才能創建緩衝圖像。 (留作'TODO' - BNI)
  4. 在構造函數或init()方法中添加一次MouseListener而不是每次調用paint。
  5. 強烈推薦Nate所有編號的筆記列表。

試試這個代碼,仔細比較它與原來的變化。

import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.Image; 
import java.awt.Dimension; 
import java.awt.event.*; 
import java.util.ArrayList; 

import java.io.*; 

import javax.imageio.ImageIO; 
import javax.swing.*; 
import java.util.Random; 

public class Gravity extends JPanel { 

    public static final int screenw = 800; 
    public static final int screenh = 600; 

    public static Random gen = new Random(); 

    public static int[] starx = new int[100]; 
    public static int[] stary = new int[100]; 
    public static Color[] starc = new Color[100]; 

    public static Image buffer; 
    public static Graphics bg; 

    public static int[] xh = new int[1000]; 
    public static int[] yh = new int[1000]; 

    public static int i = 0; 

    public static ArrayList<Integer> ptx = new ArrayList<Integer>(); 
    public static ArrayList<Integer> pty = new ArrayList<Integer>(); 
    double x = 100; 
    double y = 100; 

    Timer timer; 

    public Gravity(){ 
     // set thre PREFERRED size! 
     setPreferredSize(new Dimension(screenw, screenh)); 
     addMouseListener(new MouseListener(){ 
        public void mouseClicked(MouseEvent e){ 
         System.out.println("Mouse was clicked"); 
         timer.start(); 
        } 

        public void mouseEntered(MouseEvent arg0) {} 
        public void mouseExited(MouseEvent arg0) {} 
        public void mousePressed(MouseEvent arg0) {} 
        public void mouseReleased(MouseEvent arg0) {} 
     }); 
     ActionListener animation = new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent ae) { 
       repaint(); 
      } 
     }; 
     timer = new Timer(50, animation); 
    } 

    @Override 
    public void paintComponent(Graphics g) { 
     buffer = createImage(screenw, screenh); 
     bg = buffer.getGraphics(); 

     int w = getWidth(); 
     int h = getHeight(); 

     double px = getWidth()/2; 
     double py = getHeight()/2; 

     bg.setColor(Color.BLACK); 
     bg.fillRect(0, 0, w, h); //black background 

     for (int j=0; j < 100; j++){ //make stars 
      starx[j] = gen.nextInt(w); 
      stary[j] = gen.nextInt(h); 
      starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156); 
      bg.setColor(starc[j]); 
      bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2); 
      bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]); 
     } 

     g.drawImage(buffer, 0, 0, null); 

     double xvel = -15; 
     double yvel = 10; 

     for (int j=0; j < 100; j++){ //store stars 
      starx[j] = gen.nextInt(w); 
      stary[j] = gen.nextInt(h); 
      starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156); 
     } 

     Image test = createImage(200,200); 
     Graphics testg = test.getGraphics(); 
     testg.drawLine(50,50,150,150); 

     g.drawImage(buffer, 0,0, null); 
     try { 
      Thread.sleep(33); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     bg.setColor(Color.BLACK); 
     bg.fillRect(0, 0, w, h); //black background 


     for (int j=0; j < 100; j++){ //draw stars 
      bg.setColor(starc[j]); 
      bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2); 
      bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]); 
     } 

     bg.setColor(Color.BLUE); 

     if (i > 0){ 
      for (int z=0; z < i-1; z++){ 
       bg.drawLine(ptx.get(z), pty.get(z), ptx.get(z+1), pty.get(z+1)); 
      } 
     } 

     bg.setColor(Color.CYAN); 
     bg.fillOval((int)px, (int)py, 25, 25); //planet 

     bg.setColor(Color.RED); 
     bg.fillRect((int)(x-5),(int)(y-5),10,10); //ship 

     double fg = (5*50000)/(Math.pow(dist(x,y,px,py),2)); 

     double m = (y-py)/(x-px); 
     double ms = Math.sqrt(Math.abs(m)); 
     if (m < 0) ms = -ms; 

     double xchg = fg; 
     double ychg = fg*ms; 

     if (x > px){ 
      xchg = -xchg; 
      ychg = -ychg; 
     } 

     xvel += xchg; 
     yvel += ychg; 

     x += xvel; 
     y += yvel; 

     ptx.add((int)x); 
     pty.add((int)y); 

     i++; 
    } 

    public static void main(String[] args){ 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       JFrame frame = new JFrame(); 

       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.getContentPane().add(new Gravity()); 
       frame.setResizable(false); 
       frame.pack(); 

       frame.setLocationByPlatform(true); 
       frame.setVisible(true); 
      } 
     }); 
    } 


    public static double dist(double x1, double y1, double x2, double y2){ 
     double x = x2-x1; 
     double y = y2-y1; 
     return Math.sqrt((x*x)+(y*y)); 
    } 
} 
1

你的paint()方法被佔用,處理鼠標點擊事件,由於在線程(!開始)循環,永不退出。啓動永遠不會是真的,因爲MouseListener的mouseClicked()永遠不會被調用,因爲paint()方法正在等待啓動爲真!如果刪除該循環,則while(true)循環將具有類似的效果。在paint()運行時發生的任何鼠標事件都將排隊,直到paint()返回。

+0

還有更多。它在前面的循環中被捕獲,直到用戶點擊動畫才結束。 –

+0

太過真實;我相應地更新了我的答案。 –

1

使用JComponent而不是Canvas。您需要將鼠標偵聽器添加到該對象。您還需要在構造函數中設置鼠標偵聽器,而不是paint()方法。

編輯:你在@AndrewThompson指出的paint()方法中做得很多。

public Gravity() { 
    addMouseListener(new MouseListener() { 

     @Override 
     public void mouseClicked(MouseEvent e) { 
      System.out.println("Mouse was clicked"); 
     } 

     @Override 
     public void mouseEntered(MouseEvent arg0) { 
     } 

     @Override 
     public void mouseExited(MouseEvent arg0) { 
     } 

     @Override 
     public void mousePressed(MouseEvent arg0) { 
     } 

     @Override 
     public void mouseReleased(MouseEvent arg0) { 
     } 
    }); 
} 

@Override 
public void paint(Graphics g) { 

    buffer = createImage(screenw, screenh); 
    bg = buffer.getGraphics(); 

    ... 

    bg.setColor(Color.BLACK); 
    bg.fillRect(0, 0, w, h); // black background 

    for (int j = 0; j < 100; j++) { // make stars 
     ... 
    } 

    bg.drawImage(title, 100, 100, null); 
    g.drawImage(buffer, 0, 0, null); 

    double xvel = -15; 
    double yvel = 10; 

    for (int j = 0; j < 100; j++) { // store stars 
     ... 
    } 

    Image test = createImage(200, 200); 
    Graphics testg = test.getGraphics(); 
    testg.drawLine(50, 50, 150, 150); 

    g.drawImage(buffer, 0, 0, null); 
    bg.setColor(Color.BLACK); 
    bg.fillRect(0, 0, w, h); // black background 

    for (int j = 0; j < 100; j++) { // draw stars 
     ... 
    } 

    bg.setColor(Color.BLUE); 

    if (i > 0) { 
     for (int z = 0; z < i - 1; z++) { 
      bg.drawLine(ptx.get(z), pty.get(z), ptx.get(z + 1), pty.get(z + 1)); 
     } 
    } 

    bg.setColor(Color.CYAN); 
    bg.fillOval((int) px, (int) py, 25, 25); // planet 

    bg.setColor(Color.RED); 
    bg.fillRect((int) (x - 5), (int) (y - 5), 10, 10); // ship 

    .... 

    ptx.add((int) x); 
    pty.add((int) y); 
} 

public static void main(String[] args) { 
    ... 

    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 

    ... 
} 

注意有關代碼:

  1. 避免讓場public static。 99.9%的時間不是必需的,並且通常會在稍後導致麻煩。
  2. 繪畫代碼似乎是不必要的使用緩衝區 - test圖像目前沒有使用!
  3. 我刪除了while(true)循環,但注意到您正在繪製圖像,修改圖像,然後再次繪製圖像。你可以一口氣做到這一點。
  4. 你應該能夠避免使用一個Image緩衝區,因爲每次調用paint()時都會創建一個新緩衝區,並在開始時清除它。只需將圖形直接畫到g即可。
  5. 避免在paint()方法中執行I/O操作。在施工期間或在後臺線程中加載圖像。