2013-07-10 22 views
2

我是Java初学者,我试图创建一个应用程序,该应用程序在光标所在的位置绘制一个矩形。我已经完成了所有工作,但是我无法使mouseMoved(MouseEvent) method重新绘制JPanel。没有重绘,矩形只能绘制一次,就是这样。随着重画,它编译好,但是当我运行它,每次移动鼠标,我得到这个大“Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException”错误。Java - 重绘JPanel给出错误

那么,任何人都可以请帮我一下吗?

import java.awt.*; 
import javax.swing.*; 
import java.awt.event.*; 
import javax.swing.event.*; 

public class Game extends JPanel implements MouseMotionListener 
{ 
    public static void main(String[] args) { 
     new Game().game(); 
    } 
    JPanel panel; 
    JButton button2; 
    JButton button; 
    public void game() { 
     JPanel panel = new Game(); 
     button = new JButton("Ok"); 
     panel.setLayout(new FlowLayout()); 
     panel.add(button); 

     button2 = new JButton("Cancel"); 

     JFrame frame = new JFrame("Game"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setSize(500,500); 
     frame.setResizable(false); 
     frame.add(panel); 

     frame.setVisible(true); 
     panel.addMouseMotionListener(this); 
    } 

    public void paintComponent(Graphics g) { 

     super.paintComponent(g); 
     PointerInfo a = MouseInfo.getPointerInfo(); 
     Point b = a.getLocation(); 
     int x = (int) b.getX(); 
     int y = (int) b.getY(); 
     g.fillRect(x,y,100,100);   
    } 

    public void mouseMoved(MouseEvent evt) { 
     panel.repaint; //This is the line of code that I need help with. Thanks! 
    } 
    public void mouseDragged(MouseEvent evt) {} 
} 
+2

1)使用代码块的一致和逻辑缩进。代码的缩进旨在帮助人们理解程序流程。 2)不要设置顶级容器的大小。而是布置内容并调用'pack()'。 –

+0

感谢您的评论安德鲁。但是如果我不调整JFrame的大小,那么它将如何知道窗口的大小? pack()是做什么的?再次感谢! –

+0

*“pack()是做什么的?”*如果您已经阅读了该方法的JavaDocs,则很可能您不必提出这些问题! –

回答

4

希望在代码示例中的注释,可以告诉你在做什么错在你的代码:-),否则总有一个理由来提出你的疑虑......

import java.awt.*; 
import javax.swing.*; 
import java.awt.event.*; 

public class Game extends JPanel { 
    /* 
    * Now x and y are instance variables, 
    * whose values you can change at each 
    * MouseMove Event, and call repaint() 
    * to see the effects 
    */ 

    private int x; 
    private int y; 
    private MouseAdapter mouseActions = 
     new MouseAdapter() { 
     @Override 
     public void mouseMoved(MouseEvent me) { 
      /* 
      * Now as the Mouse moves, we simply 
      * updating the instance variables, 
      * i.e. x and y to the new values 
      * of the Mouse Location and calling 
      * repaint() to draw the rectangle. 
      * Since this class (Game) extends JPanel, 
      * hence all the functions of the JPanel 
      * belongs to this class, hence like 
      * as we call any other method of this 
      * class, without using the object, 
      * we can call repaint, likewise. 
      */ 
      x = me.getX(); 
      y = me.getY(); 
      repaint(); 
     } 
    }; 

    /* 
    * This JPanel panel is unnecessary in 
    * this case, since the class itself 
    * extends JPanel, hence you can use 
    * this (keyword) to access the instance 
    */ 
    //JPanel panel; 
    // Not needed for this case. 
    //JButton button2; 
    //JButton button; 
    public void game() { 

     JFrame frame = new JFrame("Game"); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.setResizable(false); 
     addMouseMotionListener(mouseActions); 
     /* 
     * Here this means the instance 
     * of the current class 
     */ 
     frame.add(this); 
     frame.pack(); 
     frame.setLocationByPlatform(true); 
     frame.setVisible(true); 
    } 

    /* 
    * While overriding methods of the 
    * super class, try to keep the 
    * ACCESS SPECIFIER, as close to 
    * the original thingy as possible 
    * In this case, it's protected 
    * and not public 
    */ 
    @Override 
    protected void paintComponent(Graphics g) { 

     /* 
     * Do not perform calculation in this method 
     * atleast. 
     */ 
     super.paintComponent(g); 
     g.fillRect(x, y, 100, 100); 
    } 

    public static void main(String[] args) { 
     Runnable runnable = new Runnable() { 
      @Override 
      public void run() { 
       new Game().game(); 
      } 
     }; 
     EventQueue.invokeLater(runnable); 
    } 

    @Override 
    public Dimension getPreferredSize() { 
     return new Dimension(500, 500); 
    } 
} 
+2

+1不错,如果我必须挑剔,而是重写'JPanel'的getPreferredSize并返回所需的尺寸,并在设置'JFrame'之前移除'JFrame#setSize()'并使用'pack()': ) –

+2

@DavidKroukamp:请,如果你可以做这些改变,我太感慨了。我在iPad上,所以格式化代码对我来说会有点困难。建议是太好了,否则我必须等到早上做他编辑:(对于其余的谢谢,并保持微笑。:-) –

+3

@ncEcOw:我冒昧地做出了大卫建议的变化。 – trashgod

4

更改此:

public void game() { 
JPanel panel = new Game(); 

这样:

public void game() { 
panel = new Game(); 

你只是建立在第一种情况下的局部变量。要解决这个问题,你需要实例化类变量。