Sun wanted to decouple the look and feel of a control from its function (to fire such and such an event). They employed the Model-View-Controller pattern to solve this problem. Every GUI control has three parts: model, view, and control. The view is the look and feel of the GUI control, the control is the event firing mechanism, and the model is the
Normally we can ignore these details, but in Swing's more advanced controls the details are important.
The best example is Swing's table control.
In this example a primitive spread sheet allows users to enter two numbers in the first two columns of a table row. The last four columns display the sum., product, difference, and quotient of these two numbers:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.event.*;
We begin be defining the table control's model. This component contains the table's data (a 2D array) and the table's logic: getValueAt, setValueAt, etc:
class TableCalculator extends AbstractTableModel {
private static final long
serialVersionUID = 1L;
private String[] columnNames = {
"Input 1",
"Input 2",
"Sum",
"Product",
"Difference",
"Quotient"};
private Double[][] data = {
{10.0,
2.0, 12.0, 20.0, 8.0, 5.0},
{100.0,
20.0, 120.0, 2000.0, 80.0, 5.0},
{1.0,
1.0, 2.0, 1.0, 0.0, 1.0},
{25.0,
5.0, 30.0, 5.0, 20.0, 5.0}
};
public String[] getColumnNames() {
return columnNames; }
public int getColumnCount() {
return columnNames.length;
}
public int getRowCount() {
return data.length;
}
public Class getColumnClass(int c) {
return getValueAt(0,
c).getClass();
}
public String getColumnName(int col)
{
return columnNames[col];
}
public Object getValueAt(int row, int
col) {
return data[row][col];
}
public boolean isCellEditable(int
row, int col) {
return (col < 2);
}
public void setValueAt(Object value,
int row, int col) {
data[row][col] = (Double)value;
fireTableCellUpdated(row, col);
}
}
Note that changing a cell fires a "cell updated" event.
JTable is the view of the table model. The JTable is contained in a JPanel. The panel implements the TableModelListener. In effect, it is the control. It is notified when a cell has been edited. It responds by updating the arithmetic cells.
public class TablePanel extends JPanel implements
TableModelListener {
private static final long
serialVersionUID = 1L;
private JTable table;
public TablePanel(TableCalculator
model) {
model.addTableModelListener(this);
table = new JTable(model);
table.setPreferredScrollableViewportSize(new
Dimension(500, 70));
setLayout(new BorderLayout());
add(table.getTableHeader(),
BorderLayout.PAGE_START);
add(table, BorderLayout.CENTER);
}
public void
tableChanged(TableModelEvent e) {
int row = e.getFirstRow();
int column = e.getColumn();
if (column < 2) {
TableCalculator
model = (TableCalculator)e.getSource();
double
arg1 = (Double)model.getValueAt(row, column);
double
arg2 = (Double)model.getValueAt(row, (column + 1) % 2);
model.setValueAt(new
Double(arg1 + arg2), row, 2);
model.setValueAt(new
Double(arg1 * arg2), row, 3);
model.setValueAt(new
Double(arg1 - arg2), row, 4);
model.setValueAt(new
Double(arg1 / arg2), row, 5);
}
}
public class TableGUI {
public static void main(String[] args)
{
JFrame frame = new JFrame();
frame.setTitle("Table Calculator");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
TableCalculator model = new
TableCalculator();
TablePanel panel = new TablePanel(model);
frame.add(panel);
frame.pack(); // shrink wrap
the frame to the table
frame.setVisible(true);
}
}