patrik patrik - 6 months ago 19
Java Question

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?

Answer

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.

Comments