【问题标题】:Java - repainting JPanel gives an errorJava - 重新绘制 JPanel 会出错
【发布时间】:2013-07-10 13:53:26
【问题描述】:

我是 Java 初学者,我正在尝试创建一个应用程序,该应用程序在光标所在的位置绘制一个矩形。我已经完成了所有工作,但我无法让mouseMoved(MouseEvent) method 重新绘制JPanel。没有重绘,矩形只绘制一次,仅此而已。通过重绘,它编译得很好,但是当我运行它时,每次移动鼠标时,我都会收到这个大的“Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException”错误。

那么,有人可以帮我解决这个问题吗?

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) {}
}

【问题讨论】:

  • 1) 对代码块使用一致且符合逻辑的缩进。代码的缩进是为了帮助人们理解程序流程。 2)不要设置顶级容器的大小。而是布局内容并致电pack()
  • 感谢安德鲁的评论。但是如果我不调整 JFrame 的大小,那么它怎么知道窗口的大小呢? pack() 是做什么的?再次感谢!
  • “pack() 是做什么的?” 如果您已经阅读了该方法的 JavaDocs,那么您很可能不必问我这些问题!

标签: java swing jpanel repaint


【解决方案1】:

希望代码示例中的 cmets 能够说出您在代码中做错了什么:-),否则总有理由提出您的疑问...

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);
    }
}

【讨论】:

  • +1 很好,如果我不得不挑剔,而不是覆盖getPreferredSizeJPanel 并返回您想要的尺寸,并删除JFrame#setSize() 并在设置JFrame 可见之前使用pack() :)
  • @DavidKroukamp :拜托,如果你可以做这些改变,我太感激了。我在 iPad 上,所以格式化代码对我来说有点困难。建议太好了,否则我必须等到早上才能进行编辑:(其余的谢谢并保持微笑。:-)
  • @nIcEcOw:我冒昧地按照 David 的建议进行了更改。
  • 啊,我愿意,但@trashgod 为我们做到了:)。谢谢楼主!
  • 覆盖getPreferredSize() 是我扩展JPanel 的新ad hoc 基本原理。 :-)
【解决方案2】:

改变这个:

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

到这里:

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

在第一种情况下,您只是创建了一个局部变量。要解决此问题,您需要实例化类变量。

【讨论】:

    猜你喜欢
    • 2011-05-22
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-12
    • 2012-08-05
    • 1970-01-01
    • 2011-05-03
    相关资源
    最近更新 更多