views:

162

answers:

2

I'm using a custom JLayeredPane. I have several Shapes which needed to be drawn on different layers in the JLayeredPane.

To test this I create a JPanel and ask its graphics. Then I draw a test rectangle on that JPanel (preparing the graphics) and in my paintComponent method from the JLayeredPane I finally draw everything. But this fails (NullPointerException).

public class MyCustomPanel extends JLayeredPane {

// test
JPanel testpane;
Graphics g2;
// test

// constructor
public MyCustomPanel() {
    testpane = new JPanel();
    this.add(testpane, new Integer(14));
    g2 = testpane.getGraphics();
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);

    g2.drawRect(10, 10, 300, 300);
}

}

// run:
//Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
//        at view.MyCustomPanel.paintComponent(MyCustomPanel.java:65)

Why can't I draw on such a JPanel from within my JLayeredPane? I can draw directly on my JLayeredPane from within my paintComponent method but that's on the default Panel from the JLayeredPane. I need to create and draw on several layers which are added in my JLayeredPane.

What am I doing wrong? :s

+1  A: 

The variable g2 is probably null because you set it in the constructor, not when drawing. Instead, use the "g" that was passed in.

You can only get a legitimate Graphics from a component that is currently being painted. Otherwise, it's not valid. At the point you're requesting it, the MyCustomPanel() isn't being displayed, and neither is testpane.

Paul Tomblin
But the g is from the JLayeredPane and not from the JPanel. I need to draw that rectangle on my JFrame so I need the graphics from that JFrame and not the g (graphics) from my JLayeredPane :s
juFo
@jufo, You can only get a legitimate Graphics from a component that is currently being painted. Otherwise, it's not valid. At the point you're requesting it, the MyCustomPanel() isn't being displayed, and neither is testpane.
Paul Tomblin
+2  A: 

You should use g2 casting the Graphics that is passed to you:

Graphics2D g2 = (Graphics2D)g;

Why don't you try decoupling things?

class InnerPanel extends JPanel
{
  public void paint(Graphics g)
  {
     Graphics2D g2 = (Graphics2D)g;
     g2.drawRect(....);
  }
}

class MyLayered extends JLayeredPane()
{
  MyLayered()
  {
    this.add(new InnerPanel(), 14);
  }
}

this makes more sense..

Also because you are trying to do something that doesn't agree with Swing behaviour. Swing will care by itself to call the appropriate paint methods over things that must be displayed, and to go with this protocol you should tell Graphics objects what to draw when Swing asks it to your objects (calling the paint) method, not when you want to do it.

In this way whenever Swing wants to draw your JLayeredPane you just draw things on a Graphic object of other things without considering that Swing will call their appropriate methods when it's the right time to do so.

In conclusion: you can't draw something on a Graphic object when you want it. You can do it just inside methods invoked by Swing, because otherwise Graphics of these objects doesn't mean anything

Jack
But this will use the graphics from the JLayredPane and not from my JPanel. So I would draw on my JLayredPane and not on my JPanel ? :s
juFo
@Why don't you try decoupling things?I don't want to decouple this. How can I draw from within my JLayredPane on a JPanel without creating a custom JPanel? :s
juFo
Then you should think twice about object oriented programming, why should you want to implement custom drawing of objects outside themselves? This makes no sense.. What will you do with 5 different panels? Store all their graphics objects and draw on them on paintComponent of the layered pane?
Jack
I was going to suggest doing the rectangle drawing in the inner panel as well, but you beat me too it. +1.
Paul Tomblin