Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initialization in paintComponent doesn't work

Tags:

java

swing

I'm doing some exercise to understand Java and Swing API. Why do I have a nullPointerException in the Disegno constructor? I want to print the coordinates of the two rectangles, but they seem not to be initialitied.

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);
    }
}
like image 608
Astinog Avatar asked Jan 17 '23 04:01

Astinog


2 Answers

Others have helpfully suggested ways to detect and avoid the NullPointerException. Unfortunately, you can't rely on when your implementation of paintComponent() will be called. Instead,

  • Determine the required geometry as a function of the current widow's size; resize the window in the example below to see how yellow seems to stick to the bottom right corner.

  • Because MyPanel contains no components of its own, you should override getPreferredSize(), as @nIcE cOw shows here.

  • Use pack() to size the enclosing Window.

  • Build on the event dispatch thread.

Addendum: I can't understand why you override the method getPreferredSize().

Subclasses of JComponent override getPreferredSize() so that pack() can size the Window "to fit the preferred size and layouts of its subcomponents." That way you don't have to worry if the user has a different font, for example. MyPanel just draws geometric shapes, so you're the boss on preferred size. As discussed here, a demo may use setPreferredSize() for convenience, but you should understand the limitations of doing so.

enter image description here

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);
        }
    }
}
like image 72
trashgod Avatar answered Jan 18 '23 17:01

trashgod


You never called rect.initRect(); anywhere, that's why you getting error related to NullPointerException at those System.out.println() lines. Why you using panelObject.setVisible(true) inside each class, first add them to the JPanel and simply call setVisible(...) on the JFrame that will do. Here watch your modified code with the said thingies, working as expected :

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

If you would write a System.out.println() inside the intiRect() you will know, the lines which are giving you errors are being called before the paintComponent(...) method itself. So it appears to me, that you have to take that logic out of the paintComponent(...) method and keep it somewhere else, or else remove those lines, if you don't need them.

like image 44
nIcE cOw Avatar answered Jan 18 '23 19:01

nIcE cOw