【问题标题】:Initialization in paintComponent doesn't workpaintComponent 中的初始化不起作用
【发布时间】:2012-07-07 15:31:34
【问题描述】:

我正在做一些练习来理解 Java 和 Swing API。为什么我在 Disegno 构造函数中有一个 nullPointerException?我想打印两个矩形的坐标,但它们似乎没有被初始化。

import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Disegno extends JFrame{

    Disegno(){
        this.setSize(500, 500);
        this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
        MyPanel aba = new MyPanel();
        this.setContentPane(aba);
        this.setVisible(true);

        System.out.println(aba.rect.blue.x + "-" + aba.rect.blue.y);
        System.out.println(aba.rect.yellow.x + "-" + aba.rect.yellow.y);
    }

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

class MyPanel extends JPanel{

    JPanel up, down;
    RectArea rect;

    MyPanel(){
        this.setLayout(new BorderLayout());

        up = new JPanel();
        this.add(up, BorderLayout.NORTH);
        up.setBackground(Color.red);
        up.setVisible(true);

        down = new JPanel();
        down.setBackground(Color.green);
        this.add(down, BorderLayout.SOUTH);
        down.setVisible(true);

        rect = new RectArea();
        this.add(rect, BorderLayout.CENTER);

        this.setVisible(true);
    }
}

class RectArea extends JPanel{

    Rectangle blue, yellow;
    boolean check = false;

    RectArea(){
        super();
        this.setVisible(true);
    }

    public void initRect(){
        blue = new Rectangle(0, 0, 100, 100);
        yellow = new Rectangle(this.getWidth(), this.getHeight(), 100, 100);
        System.out.println("ok");
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        if(check == false){
            this.initRect();
            check = true;
        }

        System.out.println(this.getWidth() + "-" + this.getHeight());
        g.setColor(Color.blue);
        g.fillRect(blue.x, blue.y, blue.width, blue.height);
        g.setColor(Color.yellow);
        g.fillRect(yellow.x - yellow.width, yellow.y - yellow.height, yellow.width, yellow.height);
    }
}

【问题讨论】:

  • 我怀疑是因为 contentPane 对象未初始化。
  • sscce+1。

标签: java swing


【解决方案1】:

其他人提供了有用的建议方法来检测和避免NullPointerException。不幸的是,您不能依赖何时您的paintComponent() 实现将被调用。相反,

  • 根据当前寡妇的大小确定所需的几何形状;调整下例中的窗口大小,看看yellow 是如何粘在右下角的。

  • 因为MyPanel 不包含自己的组件,所以您应该覆盖getPreferredSize(),因为@nIcE cOw 显示here

  • 使用pack() 调整封闭Window 的大小。

  • event dispatch thread 为基础。

附录:我不明白你为什么要重写方法getPreferredSize().

JComponent 的子类覆盖getPreferredSize(),以便pack() 可以调整Window 的大小“以适应其子组件的首选大小和布局”。这样你就不必担心用户是否有不同的字体,例如。 MyPanel 只绘制几何形状,所以你是首选尺寸的老板。正如here 所讨论的,为方便起见,演示可能会使用setPreferredSize(),但您应该了解这样做的局限性。

import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
* @see https://stackoverflow.com/q/11376272/230513
*/
public class Disegno extends JFrame {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                new Disegno();
            }
        });
    }

    Disegno() {
        this.setSize(500, 500);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        MyPanel aba = new MyPanel();
        this.add(aba);
        this.pack();
        this.setLocationRelativeTo(null);
        this.setVisible(true);
    }

    class MyPanel extends JPanel {

        private JPanel up, down;
        private RectArea rect;

        MyPanel() {
            super(new BorderLayout());

            up = new JPanel();
            up.setBackground(Color.red);
            this.add(up, BorderLayout.NORTH);

            rect = new RectArea();
            this.add(rect, BorderLayout.CENTER);

            down = new JPanel();
            down.setBackground(Color.green);
            this.add(down, BorderLayout.SOUTH);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(320, 240);
        }
    }

    class RectArea extends JPanel {

        private Rectangle blue = new Rectangle(0, 0, 100, 100);
        private Rectangle yellow = new Rectangle(0, 0, 100, 100);

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            System.out.println(this.getWidth() + " x " + this.getHeight());
            g.setColor(Color.blue);
            g.fillRect(blue.x, blue.y, blue.width, blue.height);

            g.setColor(Color.yellow);
            int dx = getWidth() - yellow.width;
            int dy = getHeight() - yellow.height;
            g.fillRect(dx, dy, yellow.width, yellow.height);
        }
    }
}

【讨论】:

  • 再次+1,以获取所有信息。我刚刚意识到,OP 可以制作同一 RectArea 类的不同对象,以用作不同颜色的矩形,而不是在 RectArea 类中创建蓝色、黄色。
  • 很好的洞察力;如果您更新答案以解决此问题,请随时使用我的示例。
  • 感谢您的回答。我有另一个问题。我不明白你为什么要重写 getPreferredSize() 方法。 MyPanel 不应该与 JFrame 具有相同的大小吗? MyPanel 包含所有其他面板,不是吗? (对不起我的英语)
  • 不必如此,如这些examples所示。我也试着在上面解释更多。
【解决方案2】:

你从来没有在任何地方打电话给rect.initRect();,这就是为什么你在那些System.out.println() lines 上收到与NullPointerException 相关的错误。为什么你在每个类中使用panelObject.setVisible(true),首先将它们添加到JPanel,然后在JFrame 上调用setVisible(...),就可以了。在这里用上述的东西观察你修改过的代码,按预期工作:

import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class Disegno extends JFrame{

    Disegno(){
        this.setSize(500, 500);
        this.setDefaultCloseOperation(this.EXIT_ON_CLOSE);
        MyPanel aba = new MyPanel();
        this.setContentPane(aba);
        this.setVisible(true);

        System.out.println(aba.rect.blue.x + "-" + aba.rect.blue.y);
        System.out.println(aba.rect.yellow.x + "-" + aba.rect.yellow.y);
    }

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

class MyPanel extends JPanel{

    JPanel up, down;
    RectArea rect;

    MyPanel(){
        this.setLayout(new BorderLayout());

        up = new JPanel();
        this.add(up, BorderLayout.NORTH);
        up.setOpaque(true);
        up.setBackground(Color.red);

        down = new JPanel();
        down.setOpaque(true);
        down.setBackground(Color.green);
        this.add(down, BorderLayout.SOUTH);

        rect = new RectArea();
        rect.initRect();
        this.add(rect, BorderLayout.CENTER);
    }
}

class RectArea extends JPanel{

    Rectangle blue, yellow;
    boolean check = false;

    RectArea(){
        super();
        setOpaque(true);
    }

    public void initRect(){
        blue = new Rectangle(0, 0, 100, 100);
        yellow = new Rectangle(this.getWidth(), this.getHeight(), 100, 100);
        System.out.println("ok");
    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        if(check == false){
            this.initRect();
            check = true;
        }

        System.out.println(this.getWidth() + "-" + this.getHeight());
        g.setColor(Color.blue);
        g.fillRect(blue.x, blue.y, blue.width, blue.height);
        g.setColor(Color.yellow);
        g.fillRect(yellow.x - yellow.width, yellow.y - yellow.height, yellow.width, yellow.height);
    }
}

如果你在intiRect() 中写一个System.out.println(),你就会知道,在paintComponent(...) 方法本身之前会调用给你错误的行。所以在我看来,您必须从 paintComponent(...) 方法中取出该逻辑并将其保留在其他地方,或者如果您不需要这些行,则删除它们。

【讨论】:

  • +1 表示sscce。我提出了一个alternative,引用了你们中的一个例子。
【解决方案3】:

您正试图在您的 Disegno 构造函数中访问 aba.rect.blueaba.rect.yellow,但是在调用 RectArea.paintComponent 之前它们不会被初始化,因此它会引发 NPE。

【讨论】:

  • 但是调用了paintComponent,System.out.println(this.getWidth() + "-" + this.getHeight());在里面打印!!!
  • @Amk:你有堆栈跟踪吗?它是否告诉您 NPE 发生在哪一行?
【解决方案4】:

您确定您的代码给出了 NullPointerException ........??

因为当我运行您的代码时,它运行良好...

输出:

ok
484-442

【讨论】:

  • 我希望你正在执行正确的代码......我的意思是检查输出......我的输出是否符合你的预期??
  • +1 用于报告。由于原件的同步不正确,您可能两者运行相同的代码并获得不同的结果。这个alternative 的行为应该一致。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-15
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2017-06-29
  • 2017-12-19
相关资源
最近更新 更多