0

I'm learning about Java Swing and I have found an advanced code (in my opinion) about Swing using MVC and Observer patterns. It is very difficult for me and I try to understand it. And I have 2 questions:

  1. What exactly does DetailListener.class? It is the first time when I use .class after an interface. I have tried to search on stackoverflow about ".class syntax" and I see it can be used after a class, but I still don't understand what it does in this situation.

  2. What exactly does the method fireDetailEvent()?

Thanks in advance!

import javax.swing.JFrame;
import javax.swing.SwingUtilities;

public class App {

    public static void main(String args[]) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {

                JFrame frame = new MainFrame("Hello world Swing");
                frame.setSize(500, 400);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
                frame.setVisible(true);
            }
        });
    }
}

MainFrame

import java.awt.BorderLayout;
import java.awt.Container;

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

public class MainFrame extends JFrame {

    private JTextArea textArea;

    public MainFrame(String title) {

        super(title);

        Container c = getContentPane();

        c.setLayout(new BorderLayout()); 

        textArea = new JTextArea();

        DetailsPanel detailsPanel = new DetailsPanel();

        detailsPanel.addDetailListener(new DetailListener() {

            public void detailEventOccurred(DetailEvent event) {

                String text = event.getText();
                textArea.append(text); 
            }
        });

        c.add(textArea, BorderLayout.CENTER);
        c.add(detailsPanel, BorderLayout.WEST);
    }
}

DetailsPanel

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 = -5115286206114930420L;

    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:");

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

        JButton addBtn = new JButton("Add");

        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.gridy = 1;
        add(occupationLabel, gc);

        ////// Second column /////

        gc.anchor = GridBagConstraints.LINE_START;

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

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

        //////  Final row /////

        gc.anchor = GridBagConstraints.FIRST_LINE_START;
        gc.weightx = 10;
        gc.weighty = 10;
        gc.gridy = 2;
        add(addBtn, gc); 

        addBtn.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {

                String name = nameField.getText();
                String occupation = occupationField.getText();

                String text = name + ": " + occupation + "\n";
                System.out.println(text); 

                fireDetailEvent(new DetailEvent(this, text));

            }
        });
    }

    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); 
    }
}

DetailListener

import java.util.EventListener;

public interface DetailListener extends EventListener {

    public void detailEventOccurred(DetailEvent event);
}

DetailEvent

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;
    }
}

2 Answers2

1

1) What exactly does DetailListener.class?

From the API:

Instances of the class Class represent classes and interfaces in a running Java application.

This is somewhat confusing so let's look at a an example. Calling DetailListener.class provides its Class representation. In this specific case DetailListener.class provides a Class<DetailListener> so it's possible to do this:

Class<DetailListener> cdl = DetailListener.class;

cdl is just another variable similar to how frame is just another variable. frame happens to be a JFrame which provides some methods, while cdl is a Class<DetailListener> which provides a different set of methods.

cdl's type is a Class<DetailListener> which represents the DetailListener class.

but I still don't understand what it does in this situation

Consider this code:

listenerList.add(DetailListener.class, listener);

listenerList is of type EventListenerList. According to its API, the add(...) method parameters require a Class and a T instance. In this case, the generic T is DetailListener. So far the listener has been registered but it leads into your next question.

#2 What exactly does the method fireDetailEvent()?

When the listener was registered the listenerList keeps an internal array which can be referenced later. The array holds both the Class and the actual listener instance. So invoking

Object[] listeners = listenerList.getListenerList();

provides access to the array. In this case:

listeners[0] = DetailListener.class
listeners[1] = reference to the anonymous inner class instance created from detailsPanel.addDetailListener(...)

So the loop in fireDetailEvent(...) is guaranteed to be a multiple of 2 (0 also works if there are no registered listeners). But listenerList could hold any type of listener, so

if (listeners[i] == DetailListener.class) {

uses the Class to check for equality to make sure it's safe to caste to be able to pass the DetailEvent to the listener (which is the next element in the array). Using == (instead of .equals()) is okay in this context since DetailListener.class always provides the same Class.

Andrew S
  • 2,509
  • 1
  • 12
  • 14
0
  1. What exactly does DetailListener.class?

    DetailListener.class is a so-called class literal. Basically, it is a constant of type Class referring to the DetailListener type.

    You can find more and better explanations about this at What is a class literal in Java? and its answers.

  2. What exactly does the method fireDetailEvent()?

    Your DetailsPanel class uses an EventListenerList for handling event listeners and sending events to them.

    The comment given in class EventListenerList gives a detailed description how to use it. Read this description and you will recognize, that the methods addDetailListener, removeDetailListener and fireDetailEvent of your class DetailsPanel are written exactly following this description.

    The method fireDetailEvent fires a DetailEvent to all those listeners which have registered themselves earlier by addDetailListener.

Thomas Fritsch
  • 9,639
  • 33
  • 37
  • 49