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 |
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 |
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 |
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:
- make JFrame
- set it up
- 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 - overwrite paintComponent()
- do all drawing in paintComponent()
- add panel(s) to JFrame
- add event listener to the panel
- in the event listener, call panel.repaint() to redraw the graphics (it calls paintComponent() )
- Validate or pack the JFrame (this may not actually be necessary - you only pack() if you want COMPONENTS to be packed together)
- 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);
}
}