Graphics in Java - 3. Writing GUI programs subclassing JPanel

This shows various patterns from making a subclass of JPanel to use inside your JFrame. You have to do this if you ever want to use paintComponent() to draw on your JPanel.

You cannot draw on a JFrame, nor place GUI components on a JFrame.
Instead you do these things to a JPanel. This is then placed on the JFrame.

Various patterns for writing Swing GUI programs

Remember: Keep the graphics and drawing part of your program separate from the calculation and data management part of your program.
You frequently have two separate classes to do this.

ALERT! All the examples below all make an inner class called DrawingPanel that extends a JPanel. You do not have to do this for making GUI programs which only use components like JButtons and JLabels. It is only required when you actually draw shapes and lines on the JPanel. See the previous page for simple GUI program templates.

Pattern 1 main class extends JFrame

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

public class X extends JFrame {

   public static void main(String args[]) {
      X window = new X();
   } 

   X() {      
      DrawingPanel panel = new DrawingPanel();
      this.add(panel);
   }
   
   private class DrawingPanel extends JPanel {
      DrawingPanel() {  //constructor
      }

      @Override
      public void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.drawOval(0, 0, getWidth(), getHeight()); 
      }

   }
}
0. don't forget to import packages


1. change X to be your classname. Always "extends JFrame" 2. main() calls constructor. Your object is a JFrame type object
3. Constructor makes JPanel and adds it to JFrame You may want to make DrawingPanel a global (instance) variable 4. DrawingPanel is an inner private class that extends JPanel 5. All graphics is done here on the Graphics object

In pattern 1, you can set up the properties of the JFrame either
(i) in main(): window.setSize(500,500)
or (ii) in the constructor: this.setSize(500,500)

Pattern 2 main class extends nothing

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

public class X {

   public static void main(String args[]) {
      JFrame window = new JFrame();
   
      DrawingPanel panel = new DrawingPanel();
      window.add(panel);
   }
   
   private class DrawingPanel extends JPanel {
      DrawingPanel() { }

      @Override
      public void paintComponent(Graphics g) {              
      }   
  }
}
0. don't forget to import packages


1. change X to be your classname. 2. main() makes the JFrame
It also makes a JPanel and adds it
3. DrawingPanel is an inner private class that extends JPanel 4. All graphics drawing is done here

In pattern 2, you can only set up the properties of the JFrame in main(): window.setSize(500,500)

Pattern 3 main class extends JPanel

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

public class X extends JPanel {

   public static void main(String args[]) {
      JFrame window = new JFrame();
   
      X panel = new X();
      window.add(panel);
   }
   
    X() {    //constructor
   }
   @Override
   public void paintComponent(Graphics g) {              
   } 
}
0. don't forget to import packages


1. change X to be your classname. 2. main() makes the JFrame. Do all JFrame setup here.
It also makes a JPanel and adds it
3. X is a JPanel subclass, so put everything into the constructor 4. All graphics drawing is done here

In pattern 3, you can only set up the properties of the JFrame in main(): window.setSize(500,500)

Order of events

This is generally the order of things that you do to make a GUI:

  1. make JFrame
    1. set it up
  2. make an inner class that is subclass of JPanel
    eg. class GrPanel extends JPanel
    or DrawingPanel, PaintPanel or whatever you want to call the class
    1. overwrite paintComponent()
    2. do all drawing in paintComponent()
  3. add panel(s) to JFrame
  4. add event listener to the panel
  5. in the event listener, call panel.repaint() to redraw the graphics (it calls paintComponent() )
  6. Validate or pack the JFrame (this may not actually be necessary - you only pack() if you want COMPONENTS to be packed together)
  7. set the JFrame to be visisble

How to save the drawing on the JPanel to a file

/* This method will save an image to the specified filename. 
   The image is a copy of whatever you have drawn on your JPanel
   (DrawingPanel). It is assumed to be a global variable called 'panel',
   but you could pass it in as a parameter.
   The location of the file written depends on the IDE. */

void saveImage(String filename){
    BufferedImage imagebuf=null;
    try {
        imagebuf = new Robot().createScreenCapture(panel.bounds());
    } catch (AWTException e) {        
        System.out.println("Error capturing JPanel drawing");
        return;
    }  
     Graphics2D graphics2D = imagebuf.createGraphics();
     panel.paint(graphics2D);
     try {
        ImageIO.write(imagebuf,"png", new File(filename));
    } catch (Exception e) {        
        System.out.println("Error writing file: " + filename);
    }
}