The Basic Structure:
The extends
keyword means that DrawPanel
inherits from JPanel
. In other words, DrawPanel
"is a" JPanel
. As such, it can override its methods (the ones that aren't marked final
). You might want to do that for several reasons. For example, you might want to gain access to the panel's Graphics
class, which you could use to draw a circle on the panel, or a bar graph, or a string of text.
If you don't override any methods, then when you extend JPanel
you get something like this:
public class DrawPanel extends JPanel {
//TODO not much
}
However, that's not very useful ...unless you just don't like the name JPanel
and want to call it AwesomePanel
instead (note: don't do that). If that's all you have, you're better off just creating an instance of JPanel
, like this: JPanel drawPanel = new JPanel();
paintComponent:
The purpose of extending a JPanel
is to override the paintComponent
method. The JPanel
is invisible until you override paintComponent
(note: being invisible is what makes it a useful container for buttons and other components). You are right that the paintComponent
method is pre-defined (in the JComponent
class if you were wondering), but all that method does is make an empty JPanel
. If you want to draw something on the panel, then you need to override it, like this:
public class DrawPanel extends JPanel {
@Override public void paintComponent(Graphics g) { // <-- HERE!
//TODO draw stuff
}
}
note: the @Override
part is not strictly necessary but it's good practice to include it because it reduces the number runtime errors and improves code readability
You now have access to the Graphics
object g
for the panel. Graphics
is a helper class that allows you to draw things on the panel, like this:
public class DrawPanel extends JPanel {
@Override public void paintComponent(Graphics g) {
g.drawOval(50, 50, 50, 50); // <-- draws an oval on the panel
}
}
super.paintComponent:
helpful metaphor (that I just made up): The JPanel
is the canvas, the Graphics
object is your paintbrush, and super.paintComponent(g)
is your eraser. (Also, JFrame
is your easel.)
So super.paintComponent(g)
invokes the paintComponent
method from the superclass of JPanel
(the JComponent
class) to erase whatever is currently drawn on the panel. This is useful for animation.
For example, consider drawing an analog clock on the panel. You need to refresh it every second, so each second you have to erase the previous clock and redraw the clock, adjusting the second hand. If you don't invoke super.paintComponent(g)
before redrawing the clock, it will just keep drawing new clocks on top of the old clocks and in 60 seconds what you'll have is just a filled in circle, more or less.
Only one more thing to remember: always call super.paintComponent(g)
first in the paintComponent
method, like this:
public class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g); // <-- HERE!
g.drawOval(50, 50, 50, 50);
}
}
That's it. Feel free to contact me.
Example:
I created a simple example that uses these concepts to display a string of text on a panel (which is placed inside a frame). Save in your IDE as TestPanel.java.
import java.awt.*;
import java.util.*;
import javax.swing.*;
/**
* A frame containing a panel that is sometimes red and sometimes
* blue. Also, it displays the word to go with it.
*
* Inspired by www.sometimesredsometimesblue.com.
*
*/
public class TestPanel extends JPanel {
private Random random = new Random();
private boolean isRed;
private String s = "";
public TestPanel() {
//randomly determine whether the background should be red
isRed = random.nextBoolean();
//set the background to blue
setBackground(Color.BLUE);
s = "BLUE";
//if 'isRed' is true, set the background to red
if (isRed) {
setBackground(Color.RED);
s = "RED";
}
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//write either "RED" or "BLUE" using graphics
g.setColor(Color.WHITE);
g.setFont(new Font("serif", Font.BOLD, 60));
g.drawString(s, getWidth() / 2 - g.getFontMetrics().stringWidth(s) / 2,
getHeight() / 2 + g.getFontMetrics().getHeight() / 2);
}
//main method: create an instance of TestPanel and output it on a JFrame
public static void main(String[] args) {
JFrame f = new JFrame();
f.setSize(500, 500);
f.setTitle("Sometimes Red, Sometimes Blue");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new TestPanel());
f.setVisible(true);
}
}