I am new to Java and as an exercise I am trying to develop the following: 2 JPanels on a JFrame where 1 of the JPanels can be used for drawing. I started from an example from Daniweb from 2010 but can't seem to get a graphic context because the compiler gives me a null pointer exception. The program compiles and runs fine with the g.drawRect(100,0,150,50); commented out. The broader question is, how do I tell the program that I want to draw in a specific panel? My code is enclosed -- what am I doing wrong? Thanks, Bobonoinc

import java.awt.*;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.FlowLayout;

         
public class LinePaintDemo extends JPanel{

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(Color.BLUE);
        g.drawLine(0, 0, getWidth(), getHeight());
        g.drawLine(getWidth(), 0, 0, getHeight());
    }

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            JFrame frame = new JFrame();
            frame.setSize(300,300);                  
            frame.setLayout(new FlowLayout(FlowLayout.LEFT));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            JPanel contPanel = new JPanel();
            contPanel.setBackground(Color.red);
            contPanel.setPreferredSize(new Dimension(50, frame.getSize().height));
            frame.add(contPanel);

            LinePaintDemo canvase = new LinePaintDemo();
            canvase.setBackground(Color.green);
            canvase.setPreferredSize(new Dimension(200, frame.getSize().height)); 
            frame.add(canvase);

            Graphics g = canvase.getGraphics();
//       g.drawRect(100,0,150,50);

            frame.setVisible(true);
        }
    });
  }
}
frame.setVisible(true);
Graphics g = canvase.getGraphics();
g.drawRect(0,0,50,50);

Getgraphics take graphics when frame is visible, You just have to get graphics after setting it visible.... Simple Solution :)

Edited 5 Years Ago by Majestics: n/a

Normally drawing on a GUI component is done in the paintComponent method.

The super call will immediately clear whatever was painted outside.

Edited 5 Years Ago by NormR1: n/a

Thanks for the suggestions. I moved the frame.setVisible(true); statement above getGraphic()and the program now compiles and runs. However, the g.drawRect() statement does not appear to work -- I get both JPanels and the "X" in the canvase panel but the square does not appear. I did a test by putting the g.drawRect() statement in the paintComponent method and of course, the square does appear, but this is not what I want. Any suggestions?
Thanks.

this is not what I want.

Please explain what you want.
The super in the paint method call will immediately clear whatever was painted outside.

Edited 5 Years Ago by NormR1: n/a

What I would like to do is to add squares to the canvase panel based on inputs that the user will make in the contPanel. The controls have obviously not been implemented yet but the idea is that if the user were to indicate 10 squares in the contPane, then 10 squares would be drawn in the canvase. The final application is to design artwork based on arranging colored squares (like a quilt, for example). The "X" that the program currently draws is of no interest -- it is just part of the test program.
Once I understand how to draw a shape in a JPanel, I should be able to proceed with my application.

how to draw a shape in a JPanel

Normally drawing is done in the JPanel's paintComponent method. The program logic determines what shapes are to be drawn and where, saves that information for the paint method to use and then calls repaint which causes the paint method to be called where the shapes are drawn.
There is no need to draw anything outside of the paint method.

Another method is to create an image using createImage() and draw on that anywhere in you code you want and then call repaint which calls paint which you can code to draw the built image on its Graphics context that has been built by your code somewhere else.

Edited 5 Years Ago by NormR1: n/a

OK, but the argument of the paintComponent method is (Graphics g), so how could I introduce parameters to position and size my squares? Do I create another method in the LinePaintDemo class, say drawSquare(int a, int b, int c, int d) and then call this from canvase as canvase.drawSquare(); ?

You could call your draw method from the paintComponent method and pass it the Graphics reference. The draw method would get its coordinates of where to draw from where ever you put them.

Thanks for all of your suggestions. I will explore and report back tomorrow.

If I may point out, drawing graphics does NOT belong to a panel (or any other container) other than the (virtual) screen.
You can draw anywhere on the screen.

Huge thanks to Majestics and NomR1. With your suggestions, which were right on, I was able to solve my problem, but more importantly, I learned a lot about java and object oriented programming. The final breakthrough was NormR1's last comment.

Before I close this thread, I have another question. Is there a way to "buffer" the graphic contents of a JPanel so that each time repaint() is called, the contents of the JPanel are NOT erased. I would like to accumulate the graphics without knowing in advance what they will be. In other words, if I have a set of controls in another panel that would allow the user to add different graphics at different positions within a JPanel (canvase in my example), I would want these graphics to be accumulated.

Thanks, Bob

I would like to accumulate the graphics

This sounds like what you do when double buffering.
Create a buffered image and save it. Draw each each line or shape on it as the program progresses. Have the paintComponent method draw the current version of the image.
The buffered image would contain all the drawings done earlier.

Comments
Agreed. This is the way to go.

Thanks to Majestics and NormR1 for their help in solving this problem.

This question has already been answered. Start a new discussion instead.