The program in Listing 13.1 has two problems:
If you resize the frame, the line disappears.
It is awkward to program because you have to make sure that the component is displayed before obtaining its Graphics object using the getGraphics() method. For this reason, lines 21 and 22 are placed after the frame is displayed in line 18.
Because of these two problems, you should avoid programming using the getGraphics() method. To fix the first problem, you need to know its cause. When you resize the frame, the JVM automatically invokes the paintComponent method of a Swing component (e.g., a JLabel ) to redisplay the graphics on the component. Since you did not draw a line in the paintComponent method, the line is gone when the frame is resized. To permanently display the line, you need to draw the line in the paintComponent method. The signature of the paintComponent method is as follows :
protected void paintComponent(Graphics g)
This method, defined in the JComponent class, is invoked whenever a component is first displayed or redisplayed. The Graphics object g is created automatically by the JVM for every visible GUI component. The JVM obtains the Graphics object and passes it to invoke paintComponent .
In order to draw things on a component (e.g., a JLabel ) consistently, you need to declare a class that extends a Swing GUI component class and overrides its paintComponent method to specify what to draw. The program in Listing 13.1 can be rewritten as shown in Listing 13.2. The output is the same as shown in Figure 13.4. When you resize the frame, the JVM invokes the paintComponent method to repaint the line and the text.
1 import javax.swing.*; 2 import java.awt.Graphics; 3 4 public class TestPaintComponent extends JFrame { 5 public TestPaintComponent() { 6 add( new NewLabel( "Banner" ) ); 7 } 8 9 public static void main(String[] args) { 10 TestPaintComponent frame = new TestPaintComponent(); 11 frame.setTitle( "TestPaintComponent" ); 12 frame.setLocationRelativeTo( null ); // Center the frame 13 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 14 frame.setSize( 200 , 100 ); 15 frame.setVisible( true ); 16 } 17 } 18 19 class NewLabel extends JLabel { 20 public NewLabel(String text) { 21 super (text); 22 } 23 24 protected void paintComponent(Graphics g) { 25 super .paintComponent(g); 26 g.drawLine( , , 50 , 50 ); 27 } 28 } |
The paintComponent method is automatically invoked to paint graphics when the component is first displayed or whenever the component needs to be redisplayed. The text "banner" is drawn in the paintComponent method defined in the JLabel class. Invoking super.paintComponent(g) (line 25) displays the text in the label, and invoking the drawLine method (line 26) draws a line.
The JVM invokes paintComponent to draw things on a component. The user should never invoke paintComponent directly. For this reason, the protected visibility is sufficient for paintComponent .