SOURCECODE |
How to... create an editable Table
Description:
Tables are not only useful to display the content of data containers, but also to edit it.
To do so, you may define certain columns as editable. The processing of a cell in a column is then being done by a javax.swing.table.TableCellEditor, which you add in the TableEntryDescriptor of your editable table.
As you can see, the TableCellEditor interface can be found in the javax package and is not part of the SalesPoint classes. There you can also find implementations of it, like the DefaultCellEditor, which provides three JComponents to edit the value of a cell: A JCheckBox, a JComboBox and a JTextField. For more information on the DCEE, please refer to the Java API documentation (version 1.3) of java.sun.com.
This example shows how the EditableVideoStockTED of the VideoMachine works.
ToDo's:
- Extend the AbstractTableEntryDescriptor
- Add the CountingStock with the videos to be edited to the attributes
- Add the necessary TableCellRenderers to the attributes. Here we need one to render the prices, the names and the number of videos in stock
- The CountingStock to be edited is resolved best as a parameter of the constructor
- Initialize the attributes. The CurrencyRenderer is a SalesPoint extension of the DefaultTableCellRenderer and renders the NumberValues of a Currency to be displayed like "20,00 Eur". The other two Renderers will both as DefaultTableCellRenderers render the name and amount entries, which could also be done by one, but we want to display the amount entries aligned horizontally, which is being set next.
- Set the number of columns to 5, one for the name, two for the QuoteValue (Bid / Sell), one for the number in Stock and one for the number of rented videos.
- Set the head of the columns. Here we just use an array of Strings and resolve the name by its index.
- Assign the TableCellRenderers to the columns, starting with zero for the first column from the left. The switch construction is quite useful for such tasks.
- Because of the TableCellRenderers there need no ColumnClasses to be defined.
- Set the columns 1 and 2 to be editable
- Assign the TableCellEditors to the columns. We use the DMCellEditor of the VideoMachine here for the column 1 and 2.
- Define how to resolve the value to be put into the cells. With the CountingStock as attribute it is quite easy to resolve the containing data.
- Define how to set the edited values to the VideoCassette they belong to. Here we simply put the entered value into a QuoteValue and set it by calling
VideoCassette.setValue(Value, Value)
. The validity of an entry is being tested by the DMCellEditor. For more information about it, please refer to "How to define a TableCellEditor".
Uses:
AbstractTableEntryDescriptor CountingStockImpl
import sale.*;
import data.*;
import data.ooimpl.*;
import data.swing.*;
import data.events.*;
import users.*;
import util.swing.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
1
//extend the AbstractTableEntryDescriptor
public class EditableVideoStockTED extends AbstractTableEntryDescriptor {
2
//add the data container to the attributes to easier resolve the VideoCassettes
private CountingStockImpl videoCountingStock;
private DataBasket db;
3
//put the TableCellRenderers to the attributes, too
private TableCellRenderer tcrMoney;
private TableCellRenderer tcrName;
private TableCellRenderer tcrCount;
4
//resolve the CountingStock to be displayed by the parameters of the constructor
public EditableVideoStockTED(CountingStockImpl videoCountingStock, DataBasket db) {
5
//initialize the attributes
this.videoCountingStock = videoCountingStock;
this.db = db;
//define a CurrencyRenderer
tcrMoney = new CurrencyRenderer((Currency)Shop.getTheShop().getCatalog("DM"));
//and two DefaultTableCellRenderer
tcrName = new DefaultTableCellRenderer();
tcrCount = new DefaultTableCellRenderer();
//with one displaying its entries centered horizontally
((DefaultTableCellRenderer)tcrCount).setHorizontalAlignment(SwingConstants.CENTER);
}
6
//set the number of columns to 5
public int getColumnCount() {
return 5;
}
7
//return the head of the column
//here we used an Array of Strings to resolve the head by its index
public String getColumnName(int index) {
return (new String[] { "Name",
"Buy",
"Sell",
"Pieces in Stock",
"Rent Pieces"})[index];
}
8
//assign the TableCellRenderer
public TableCellRenderer getCellRenderer(int index) {
switch (index) {
//the first column from the left has the index zero
case 0:
//displays the name
return tcrName;
case 3:
//displays a number, centered as set above
return tcrCount;
case 4:
//displays a number, centered as set above
return tcrCount;
default: // 1 and 2
//displays Currency values
return tcrMoney;
}
}
9
//returns null, because the TableCellRenderer is already defined
public Class getColumnClass(int index) {
return null;
}
10
//set the columns 1 and 2 (second and third!) to be editable
public boolean isElementEditable(Object record, int index) {
return ((index == 1) || (index == 2));
}
11
//assign the TableCellEditors to the editable cells
public TableCellEditor getCellEditor(int index) {
if (index == 1 || index == 2)
return new DMCellEditor(new String[1], "");
else
return super.getCellEditor(index);
}
12
//define how to resolve the entries of a row, column by column
public Object getValueAt(Object record, int index) {
//first resolve the VideoCassette
VideoCassette videoCassette =
(VideoCassette)((data.swing.CountingStockTableModel.Record)
record).getDescriptor();
int count = ((data.swing.CountingStockTableModel.Record)record).getCount();
switch (index) {
case 0:
//put the name into the first column
return videoCassette.getName();
case 1:
//the offer value into the second
return ((QuoteValue)videoCassette.getValue()).getOffer();
case 2:
//the bid value into the third
return ((QuoteValue)videoCassette.getValue()).getBid();
case 3:
//the amount of cassettes in stock into the fourth
return new IntegerValue(count);
case 4:
//and the number of cassettes rented into the fifth column
int rented = 0;
try {
Iterator i = UserManager.getGlobalUM().getUsers().iterator();
while (i.hasNext()) {
rented = rented +
((Customer)i.next()).getStoringStock().countItems(
videoCassette.getName(), null);
}
} catch (NullPointerException npe) {
System.out.println(npe);
}
return new IntegerValue(rented);
default:
return null;
}
}
13
//define how to change the edited value in the VideoCassette
public void setValueAt(Object record, int index, Object value) {
//resolve the edited VideoCassette
VideoCassette videoCassette =
(VideoCassette)((data.swing.CountingStockTableModel.Record)
record).getDescriptor();
try {
//get the origin of it
VideoCassette videoCassetteToEdit =
(VideoCassette)videoCountingStock.getCatalog(null).get(
videoCassette.getName(), db, true);
//get the old quoteValue
QuoteValue quoteValue = (QuoteValue)videoCassetteToEdit.getValue();
if (index == 1)
//set the value to the offer value (bid stays the same,
//that's why quoteValue.getBid() is being put here)
videoCassetteToEdit.setValue(
new QuoteValue(quoteValue.getBid(), (Value)value));
if (index == 2)
//set the value to the bid value (bid stays the same,
//that's why quoteValue.getOffer() is being put here)
videoCassetteToEdit.setValue(
new QuoteValue((Value)value, quoteValue.getOffer()));
//catch the VetoExeption thrown by editing the VideoCassette
} catch (VetoException ve) {
JOptionPane.showMessageDialog(null, ve);
}
}
}