Java Swing: Events (Video Tutorial Part 5)

A tutorial on how to implement custom events and how to deal with events generally in Java Swing applications. This tutorial shows you how to wire up your Swing app, so that the different parts of the application can communicate with each other using events routed through a central controller object, helping to prevent your app becoming a rat's nest.

After starting the video, click the maximise button to make it fullscreen so you can see the code!




Code For This Tutorial



Main.java: the main application

 
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
 
public class App {
 
    public static void main(String[] args) {
 
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new MainFrame("Hello World Swing!");
                frame.setSize(500, 400);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}
 

MainFrame.java: this implements the main frame window. Notice that it also acts as a controller, listening to events on the DetailsPanel and relaying them to the text area.

 
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;


public class MainFrame extends JFrame {
    
    private DetailsPanel detailsPanel;
    
    public MainFrame(String title) {
        super(title);
        
        // Set layout manager
        setLayout(new BorderLayout());
        
        // Create Swing component
        final JTextArea textArea = new JTextArea();

        detailsPanel = new DetailsPanel();
        
        detailsPanel.addDetailListener(new DetailListener() {
            public void detailEventOccurred(DetailEvent event) {
                String text = event.getText();
                
                textArea.append(text);
            }
        });
        
        // Add Swing components to content pane
        Container c = getContentPane();
        
        c.add(textArea, BorderLayout.CENTER);
        c.add(detailsPanel, BorderLayout.WEST);
    }
}



 

DetailsPanel.java: implements a panel with a couple of text fields and a button. This class fires DetailEvents.

 
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.EventListenerList;

public class DetailsPanel extends JPanel {

    private static final long serialVersionUID = 6915622549267792262L;
    
    private EventListenerList listenerList = new EventListenerList();

    public DetailsPanel() {
        Dimension size = getPreferredSize();
        size.width = 250;
        setPreferredSize(size);

        setBorder(BorderFactory.createTitledBorder("Personal Details"));

        JLabel nameLabel = new JLabel("Name: ");
        JLabel occupationLabel = new JLabel("Occupation: ");

        final JTextField nameField = new JTextField(10);
        final JTextField occupationField = new JTextField(10);

        JButton addBtn = new JButton("Add");

        addBtn.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                String name = nameField.getText();
                String occupation = occupationField.getText();

                String text = name + ":  " + occupation + "n";
                
                fireDetailEvent(new DetailEvent(this, text));
            }
        });

        setLayout(new GridBagLayout());

        GridBagConstraints gc = new GridBagConstraints();

        // // First column /////////////////////////

        gc.anchor = GridBagConstraints.LINE_END;
        gc.weightx = 0.5;
        gc.weighty = 0.5;

        gc.gridx = 0;
        gc.gridy = 0;
        add(nameLabel, gc);

        gc.gridx = 0;
        gc.gridy = 1;
        add(occupationLabel, gc);

        // // Second column
        gc.anchor = GridBagConstraints.LINE_START;

        gc.gridx = 1;
        gc.gridy = 0;
        add(nameField, gc);

        gc.gridx = 1;
        gc.gridy = 1;
        add(occupationField, gc);

        // Final row
        gc.weighty = 10;

        gc.anchor = GridBagConstraints.FIRST_LINE_START;
        gc.gridx = 1;
        gc.gridy = 2;
        add(addBtn, gc);
    }
    
    public void fireDetailEvent(DetailEvent event) {
        Object[] listeners = listenerList.getListenerList();
        
        for(int i=0; i < listeners.length; i += 2) {
            if(listeners[i] == DetailListener.class) {
                ((DetailListener)listeners[i+1]).detailEventOccurred(event);
            }
        }
    }

    public void addDetailListener(DetailListener listener) {
        listenerList.add(DetailListener.class, listener);
    }

    public void removeDetailListener(DetailListener listener) {
        listenerList.remove(DetailListener.class, listener);
    }
}

 

DetailEvent.java: here's the DetailEvent class. This is used to pass information from the DetailsPanel to listening classes (MainFrame in this case).

 
import java.util.EventObject;


public class DetailEvent extends EventObject {
    
    private String text;
    
    public DetailEvent(Object source, String text) {
        super(source);
        
        this.text = text;
    }
    
    public String getText() {
        return text;
    }
}

 

DetailListener.java: here's the specification for what a class that listens to DetailEvents must look like.

 
import java.util.EventListener;

public interface DetailListener extends EventListener {
    public void detailEventOccurred(DetailEvent event);
}