javaswingeventsabstracttablemodeltablerowsorter

How are listeners handled in Java Swing?


The question is how swing handles listeners. In this example it is the TableModelListener which is in focus.

The table model (let us call it TableModelImpl) I have is extended from AbstractTableModel. Between this table model and the JTable I have class called TableSorter, which is like a decorator to TableModelImpl (and the TableSorter also extends AbstractTableModel). The TableSorter is linked to TableModelImpl via association, so what I mean is that TableSorter holds a reference to the TableModelImpl. Further, the TableSorter have member of type TableModelListener, which listen to my TableModelImpl object. The JTable does in turn listen to a TableSorter.

So in general it can be said that the JTable object listens to TableSorter, which listens to my TableModelImpl. So the question is: How does this work? Assume for example that I want to call TableModelStructureChanged() on my TableModelImpl object, will this Event be forwarded to the JTable via the TableSorter then?

So, some shortened example:

public class TableModelImpl extends AbstractTableModel {

private boolean enabled;
public TableModelImpl(//non relevant parameter, linked to data) {
    //Irrelevant code binds model to the data
    this.enabled = false;
}

public void setEnabled(boolean enabled) {
    this.enabled = enabled;
    fireTableStructureChanged();
}
    // More irrelevant code
}

public class TableSorter extends AbstractTableModel {

private TableModel tableModel;

    private MouseListener mouseListener;
    private TableModelListener tableModelListener;

    public TableSorter() {
        this.mouseListener = new MouseHandler();
        this.tableModelListener = new TableModelHandler();
    }

    public TableSorter(TableModel tableModel) {
        this();
        setTableModel(tableModel); //Adds this.tableModelListener to tableModels listenerList
    }
}

So if I do following:

TableModelImpl tm = new TableModelImpl();
TableSorter sorter = new TableSorter(tm);
JTable table = new JTable(sorter);
tm.setEnabled(true);

Will the JTable be notified?


Solution

  • Swing is a great implementation of most well-known design patterns in java such as Model-View-Controller(most of times referred to as MVC), Singleton, Factory, Observer and etc.

    Many JComponents such as JTable, JList or JComboBox are implementing MVC pattern.

    In many situations when the model is changed, a method like fireTableDataChanged() is getting called, which is responsible for iterating over the list of listeners added to the model and call their tableChanged(TableModelEvent tme) method. So any other component such as the view will be notified to update it's state due to the changes of the model.

    The same is applied when fireTableStructureChanged() is called. Since JTable is implementing the TableModelListener interface and register itself as a listener to it's TableModel, it will be notified automatically when you call fireTableStructureChanged().

    It's beneficial to see the source code of the JTable and AbstractTableModel to understand the mechanism of firing and listening to the TableModelEvents.

    [UPDATE]

    There is not a magic way, just method calls. In the AbstractTableModel there is a List<TableModelListener> called listenerList. On the other hand, JTable is implementing TableModelListener interface. In the constructor of JTable class, JTable adds itself to the list of listeners in the model. So when anything happens to TableModel and its fireXXX() methods are getting called, the only magic is iterating over listenerList and calling 'tableChanged' method. Since JTable is in the list, then 'tableChanged' of JTable is called.

    Hope this would be helpful.