JFrame vs. JComponent(s)
JComponent
- JPanel - JLabel - JButton - JTextFieldEvents and Listeners
Examples
All JComponents have the method:
void paintComponent(Graphics g);
However, a JFrame does not.
A JFrame has a contentPane.
In general, JComponents should be added to the contentPane of a JFrame and then manipulated, while using the JFrame as a window container.
For example, a JPanel added to a JFrame can be used for drawing.
Note also that JPanel's can themselves be containers for other JComponents.
This can help with the layout of a graphical interface.
Different components have default Layout Managers that determine how components are placed when they are added.
Two such managers are:
1. FlowLayout // Default for JPanel 2. BorderLayout // Default for JFrame's content pane.
This just adds components to the container from left to right until the width of the container is reached, then continues at the left below the the first row of components, etc.
The height of a displayed row is the maximum height of the components on that row.
The components may change rows as the frame is resized.
The contentPane of a JFrame uses this layout manager.
Components should be added to one of the areas as shown below:
NORTH | ||
WEST | CENTER | EAST |
SOUTH |
If an area has no components, the other areas expand to use its space.
If two components are added to the same area, the one added last will be "on top" and will be the only one displayed.
Instances of this class are window "frames."
The simlplest way to use the class is to create a class that inherits from JFrame.
Then there are 4 settings to make after creating an instance, e of your class before the frame becomes visible.
1. Set the close action. 2. Set the size of the frame 3. Set the location of the frame on the screen 4. Make the frame visible.
When the user clicks the X in the frame's border, you usually want the frame to close and the program to exit.
In some applications you might want to make a frame be visible sometiems and hidden at other times.
One operation is to HIDE the frame without actually destroying it.
If the frame is hidden, it isn't visible, but the frame object still exists and can be made visible again without having to recreate it.
The JFrame method for setting the default operation is:
public void setDefaultCloseOperation(int operation) Some possible values for the operation are predefined int constants in JFrame: EXIT_ON_CLOSE HIDE_ON_CLOSE DO_NOTHING_ON_CLOSE
The user is expected to provide customized action in a separate method if DO_NOTHING_ON_CLOSE is set as the default operation.
1 public class ex1 extends JFrame 2 { 3 public ex1() 4 { } 5 6 public static void main(String[] args) 7 { 8 ex1 e = new ex1(); 9 e.setDefaultCloseOperation(EXIT_ON_CLOSE); 10 e.setSize(new Dimension(200,100)); 11 e.setLocation(300,300); 12 e.setVisible(true); 13 } 14 }
Visual Components are added to the contentPane of a JFrame.
JPanel is a general component that has an associated Graphics context and methods can be used to draw text or graphic shapes on the JPanel.
JComponent's all have a default method for drawing themselves:
In JPanel: public void paintComponent(Graphics g)
This method is not called directly from your code.
That's good because you would have to pass it a Graphics object and where do you get one? (Well there is a Graphics class, but its abstract.)
A separate thread is created that executes the paintComponent method for all components in the JFrame's content pane whenever necessary.
That is, if the frame is minimized, maximized or changes size, the paintComponent method for each component in the frame is executed again.
This style of method execution is called event-driven execution.
The paintComponent method is executed whenever one of the resizing or minimizsing events takes place rather than being called from code you might write.
So in general, you should never call paintComponent directly.
There is a slight catch, however, JPanel's paintComponent method clears the JPanel with the default background color, but doesn't do any other drawing.
You can do a few things like setting the background color of the JPanel.
But you will generally need to define a subclass of JPanel so that you can override the paintComponent method.
The JPanel subclass instance may need to know about the JFrame it is contained in (its size for example).
So usually this class is made a non-static inner class.
The Graphics object passed to the paintComponent method can be used to draw text or graphic shapes on the associated component.
Somc Graphics methods:
public void setColor(Color c) public void drawString(String s, int x, int y) public drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) public fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
The arc methods draw in a rectangle whose upper left corner is at (x,y) and has the specified width and height.
Here is a subclass of JPanel. Its main virtue is that it lets us redefine the paintComponent method.
This particular paintComponent method will
Note: Dimension is a class with two int data members: x and y.
The JFrame's getSize method returns a Dimension object that contains the width (x) and the height( y) of the JFrame's content pane.
1 private class DrawPanel extends JPanel 2 { 3 private String msg; 4 private int redrawCnt = 0; 5 6 public DrawPanel() 7 { 8 super(); 9 msg = "A DrawPanel"; 10 } 11 public DrawPanel(String m) 12 { 13 super(); 14 msg = m; 15 } 16 public void paintComponent(Graphics g) 17 { 18 super.paintComponent(g); 19 Dimension d = getSize(); 20 redrawCnt++; 21 22 g.setColor(Color.blue); 23 g.drawString(msg + "(" + redrawCnt + ")", 24 d.width/2 - 3 * msg.length(), d.height/2); 25 g.setColor(Color.red); 26 g.fillArc(-40,-40,80,80,-90, 90); 27 } 28 }
The ex1a class
1 public class ex1a extends JFrame 2 { 3 JPanel drawPanel; 4 private class DrawPanel extends JPanel 5 { 6 .... // As above 7 } 8 9 // Constructor (ex1a is the containing JFrame, not the JPanel) 10 public ex1a() { 11 drawPanel = new DrawPanel("Hello, World!"); 12 drawPanel.setBackground(Color.white); 13 14 Container cpane = this.getContentPane(); 15 cpane.add(drawPanel, BorderLayout.CENTER); 16 17 } 18 19 public static void main(String[] args) { 20 ex1a e = new ex1a(); 21 e.setDefaultCloseOperation(EXIT_ON_CLOSE); 22 e.setSize(new Dimension(300,250)); 23 e.setLocation(300,300); 24 e.setVisible(true); 25 } 26 }
These two examples don't do anything after the frame is displayed.
There is one exception, the user can close the frame.
This event is handled by the frame and the action is to exit. (EXIT_ON_CLOSE).
In general different components will be capable of responding to certain events.
Some additional component classes are:
A JTextField is a box that the user can type into, but it has only one row.
A JTextArea is similar, but can have mulitple rows and can be used for typing longer unformatted text.
Here are some events that these components respond to:
For a JTextField, the event is triggered when the user types a return.
Otherwise, the user can backspace, delete characters, etc. before an event is triggered.
For each of the events in the table below there is a corresponding Listener Type. These Listener Types are Java interfaces.
Event | Listener Type |
---|---|
Button click Press return in text field, Select an item in a list |
ActionListener |
Close a frame | WindowListener |
Press a mouse button (in a component) | MouseListener |
Move or drag a mouse | MouseMotionListener |
Component becomes visible | ComponentListener |
Gain/Loose Focus | FocusListener |
Table or List selection changes | ListSelectionListener |
Examine the methods of the component. If a component has a method
addActionListener
then it responds to an ActionEvent.
There are two general ways to implement a listener for a component:
1. By creating an anonymous class instance as the parameter to the appropriate addXXXListener method. 2. By having the class that contains the component implement the XXXListener interface.
import javax.swing.*; import java.awt.*; import java.awt.event.*; public class ex1 extends JFrame { private JButton btnExit; private JButton btnGreeting; private Container cntPane; public ex1() { cntPane = getContentPane(); btnExit = new JButton("Exit"); btnExit.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }); btnGreeting = new JButton("Greeting"); btnGreeting.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { JOptionPane.showMessageDialog(null, "Hello, World!"); } }); cntPane.add(btnExit); cntPane.add(btnGreeting); } public static void main(String[] args) { ex1 app = new ex1(); app.setSize(300,300); app.setLocation(200,100); app.setDefaultCloseOperation(EXIT_ON_CLOSE); app.setVisible(true); } }
This example uses a JPanel component and as a container.
The following components are first added to the JPanel:
Then the JPanel and a JTextArea are added to the contentPane of the JFrame.
The JPanel is added to the BorderLayout.NORTH area.
The JTextArea is added to the BorderLayout.CENTER area.
The import statements and the main method are shown below:
1 import java.awt.*; 2 import java.awt.event.*; 3 import javax.swing.*; 4 5 public class testTextFields extends JFrame 6 { 7 private JTextField txtBox; 8 private JTextArea txtArea; 9 private JButton btnClear; 10 ... 56 57 public static void main(String[] args) 58 { 59 testTextFields app = new testTextFields("Test Text Fields"); 60 app.setSize(400,200); 61 app.setLocation(200,100); 62 app.setDefaultCloseOperation(EXIT_ON_CLOSE); 63 app.setVisible(true); 64 } 65 66 }
A JPanel is created. We aren't doing any drawing in this JPanel so we don't need to override paintComponent.
And so we don't bother creating a subclass of JPanel.
We just create a JPanel and add components to it.
5 public class testTextFields extends JFrame 6 { 7 private JTextField txtBox; 8 private JTextArea txtArea; 9 private JButton btnClear; 10 11 public testTextFields(String title) 12 { 13 super(title); 14 JPanel topPanel = new JPanel(); 15 16 // Create Components for topPanel 17 JLabel lblInput = new JLabel("Input Text: "); 18 19 txtBox = new JTextField(20); ... 29 btnClear = new JButton("Clear"); ...
The JTextField and JButton are components with which the user will interact.
We need to specify ActionListeners for each of these.
An ActionListener is an object that implements the ActionListener interface.
public interface ActionListener { public void actionPerformed(ActionEvent e); }
The steps are:
Then when an event occurs (such as clicking on the component), the actionPerformed method of the ActionListener will execute.
It is inconvenient to create a whole separate class for the ActionListener for a component since
We have to create three ActionListener's in this simple example. It could be worse for an application with many more components.
Java has a shortcut. You can create an anonymous class with an expression and directly pass this expression to addActionListner.
The advatanges are:
So the ActionListener can be created and added all at once without having write a separate named class that implements the ActionListener interface.
Lines 31 - 36 give the expression that defines the anonymous class and creates an instance of it.
This instance is then passed to the addActionListener method.
Anonymous classes are used like this with both interfaces and abstract classes.
5 public class testTextFields extends JFrame 6 { 7 private JTextField txtBox; 8 private JTextArea txtArea; 9 private JButton btnClear; 10 11 public testTextFields(String title) 12 { 13 super(title); ... 29 btnClear = new JButton("Clear"); 30 btnClear.addActionListener( 31 new ActionListener() { 32 public void actionPerformed(ActionEvent e) 33 { 34 txtArea.setText(""); 35 } 36 } );
The action listener for the JTextField is also constructed using an anonymous class.
When the user hits the enter key after typing into the one line into the JTextField,
Note: The disabled text color only needs to be set once. It should really be done in the constructor, not here in the anonymous class.
1 import java.awt.*; 2 import java.awt.event.*; 3 import javax.swing.*; 4 5 public class testTextFields extends JFrame 6 { 7 private JTextField txtBox; 8 private JTextArea txtArea; 9 private JButton btnClear; 10 11 public testTextFields(String title) 12 { ... 19 txtBox = new JTextField(20); 20 txtBox.addActionListener( new ActionListener() { 21 public void actionPerformed(ActionEvent e) 22 { 23 txtArea.setDisabledTextColor(Color.red); 24 txtArea.append( txtBox.getText() + "\n"); 25 txtBox.setText(""); 26 } 27 });
A few additional comments are required:
The rootPane manages the frame and its contentPane. Ordinarily it can be ignored. But it must be used to set the default button.
37 // Add topPanel's components 38 topPanel.add(Box.createGlue()); 39 topPanel.add(btnClear); 40 topPanel.add(lblInput); 41 topPanel.add(txtBox); 42 topPanel.add(Box.createGlue()); 43 44 45 46 txtArea = new JTextArea(10,40); 47 Font f = new Font("Arial", Font.BOLD, 16); 48 49 txtArea.setFont(f); 50 51 txtArea.setEnabled(false); 52 getContentPane().add(topPanel, BorderLayout.NORTH); 53 getContentPane().add(txtArea, BorderLayout.CENTER); 54 getRootPane().setDefaultButton(btnClear); 55 } // End of the constructor