Context Sensitive JTable
- by Geertjan
Here's a plain old JTable on the NetBeans Platform. Whenever the toolbar button is clicked, information about the currently selected row is displayed in the status bar:
Normally, the above would be achieved in NetBeans Platform applications via Nodes publishing their underlying business object when the selection changes. In this case, there are no Nodes at all. There's only a JTable and a DefaultTableModel, i.e., all pure Java Swing.
So, how does it work? To follow the logic, it makes sense to create the example yourself, starting with the Stock object:
public class Stock {
String name;
String desc;
public Stock() {
}
public Stock(String name, String desc) {
this.name = name;
this.desc = desc;
}
public String getDesc() {
return desc;
}
public String getName() {
return name;
}
public void setDesc(String desc) {
this.desc = desc;
}
public void setName(String name) {
this.name = name;
}
}
Next, create a new Window Component via the wizard and then rewrite the constructor as follows:
public final class MyWindowTopComponent extends TopComponent {
private final InstanceContent ic = new InstanceContent();
public MyWindowTopComponent() {
initComponents();
//Statically create a few stocks,
//in reality these would come from a data source
//of some kind:
List<Stock> list = new ArrayList();
list.add(new Stock("AMZN", "Amazon"));
list.add(new Stock("BOUT", "About.com"));
list.add(new Stock("Something", "Something.com"));
//Create a JTable, passing the List above
//to a DefaultTableModel:
final JTable table = new JTable(StockTableModel (list));
//Whenever the mouse is clicked on the table,
//somehow construct a new Stock object
//(or get it from the List above) and publish it:
table.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
int selectedColumn = table.getSelectedColumn();
int selectedRow = table.getSelectedRow();
Stock s = new Stock();
if (selectedColumn == 0) {
s.setName(table.getModel().getValueAt(selectedRow, 0).toString());
s.setDesc(table.getModel().getValueAt(selectedRow, 1).toString());
} else {
s.setName(table.getModel().getValueAt(selectedRow, 1).toString());
s.setDesc(table.getModel().getValueAt(selectedRow, 0).toString());
}
ic.set(Collections.singleton(s), null);
}
});
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
//Put the dynamic InstanceContent into the Lookup:
associateLookup(new AbstractLookup(ic));
}
private DefaultTableModel StockTableModel (List<Stock> stockList) {
DefaultTableModel stockTableModel = new DefaultTableModel() {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
Object[] columnNames = new Object[2];
columnNames[0] = "Symbol";
columnNames[1] = "Name";
stockTableModel.setColumnIdentifiers(columnNames);
Object[] rows = new Object[2];
ListIterator<Stock> stockListIterator = stockList.listIterator();
while (stockListIterator.hasNext()) {
Stock nextStock = stockListIterator.next();
rows[0] = nextStock.getName();
rows[1] = nextStock.getDesc();
stockTableModel.addRow(rows);
}
return stockTableModel;
}
...
...
...
And now, since you're publishing a new Stock object whenever the user clicks in the table, you can create loosely coupled Actions, like this:
@ActionID(category = "Edit",
id = "org.my.ui.ShowStockAction")
@ActionRegistration(iconBase = "org/my/ui/Datasource.gif",
displayName = "#CTL_ShowStockAction")
@ActionReferences({
@ActionReference(path = "Menu/File", position = 1300),
@ActionReference(path = "Toolbars/File", position = 300)
})
@Messages("CTL_ShowStockAction=Show Stock")
public final class ShowStockAction implements ActionListener {
private final Stock context;
public ShowStockAction(Stock context) {
this.context = context;
}
@Override
public void actionPerformed(ActionEvent ev) {
StatusDisplayer.getDefault().setStatusText(context.getName() + " / " + context.getDesc());
}
}