请问怎么对JTable的某个单元格添加一个监视器!
我建JTable用的代码
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
/**
*
* @date 23/11/2012
*/
public class ThreadTimeDemo extends JPanel {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame f = new JFrame("Test");
f.getContentPane().add(new ThreadTimeDemo(), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
});
}
private JSpinner spinnerThreadCount;
private JTextField totalTime;
private ThreadTimeTableModel model;
private JTable table;
private Action actionStart;
private final ExecutorService executor = Executors.newCachedThreadPool();
ThreadTimeDemo() {
spinnerThreadCount = new JSpinner(new SpinnerNumberModel(20, 1, 20, 1));
totalTime = new JTextField(20);
totalTime.setEditable(false);
model = new ThreadTimeTableModel();
table = new JTable(model);
table.setPreferredScrollableViewportSize(new Dimension(800, 600));
model.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
totalTime.setText(Long.toString(model.getTotalLastedTime()));
}
});
actionStart = new AbstractAction("Start") {
@Override
public void actionPerformed(ActionEvent e) {
model.clear();
Random r = new Random();
int number = ((Number)spinnerThreadCount.getValue()).intValue();
for(int i=1; i<=number; i++) {
String name = "Thread " + i;
TimeReporter reporter =
new TimeReporter(name, model, r.nextInt(50) + 10);
model.register(name);
executor.execute(reporter);
}
}
};
layoutComponents();
}
private void layoutComponents() {
setLayout(new BorderLayout());
JPanel north = new JPanel(new FlowLayout(FlowLayout.LEFT));
north.add(new JLabel("Total time : "));
north.add(totalTime);
add(north, BorderLayout.NORTH);
add(new JScrollPane(table), BorderLayout.CENTER);
JPanel south = new JPanel(new FlowLayout(FlowLayout.LEFT));
south.add(new JLabel("Number of Threads:"));
south.add(spinnerThreadCount);
south.add(new JButton(actionStart));
add(south, BorderLayout.SOUTH);
}
}
class TimeReporter implements Runnable {
private final String name;
private final ThreadTimeTableModel model;
private final int totalWork;
TimeReporter(String name, ThreadTimeTableModel model, int work) {
assert name != null;
assert model != null;
assert work > 0;
this.model = model;
this.totalWork = work;
this.name = name;
}
@Override
public void run() {
for(int i=0; i<totalWork; i++) {
model.update(name);
try {
Thread.sleep(200L);
}
catch(InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
}
class ThreadTimeTableModel extends AbstractTableModel {
private static final DateFormat DATE_FORMAT =
new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS");
private final Object writeLock = new Object();
private SortedMap<String, Long> startTimes;
private List<String> threadNames;
private volatile Map<String, Long> updateTimes;
ThreadTimeTableModel() {
startTimes = new TreeMap<String, Long>();
updateTimes = Collections.emptyMap();
threadNames = Collections.emptyList();
}
void register(String threadName) {
assert SwingUtilities.isEventDispatchThread();
startTimes.put(threadName, System.currentTimeMillis());
threadNames = Arrays.asList(
startTimes.keySet().toArray(new String[startTimes.size()])
);
}
void clear() {
assert SwingUtilities.isEventDispatchThread();
startTimes.clear();
threadNames = Collections.emptyList();
updateTimes = Collections.emptyMap();
fireTableDataChanged();
}
void update(String threadName) {
final long updateTime = System.currentTimeMillis();
synchronized(writeLock) {
Map<String, Long> newMap = new HashMap<String, Long>(updateTimes);
newMap.put(threadName, updateTime);
updateTimes = newMap;
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
fireTableDataChanged();
}
});
}
long getTotalLastedTime() {
assert SwingUtilities.isEventDispatchThread();
long result = 0;
for(int i=0; i<getRowCount(); i++)
result += getLastedTime(threadNames.get(i));
return result;
}
@Override
public int getRowCount() {
return startTimes.size();
}
@Override
public int getColumnCount() {
return 4;
}
private String formatTime(long time) {
return DATE_FORMAT.format(new Date(time));
}
private long getUpdatedTime(String threadName) {
Map<String, Long> map = updateTimes;
Long result = map.get(threadName);
if( result == null )
result = startTimes.get(threadName);
return result;
}
private long getLastedTime(String threadName) {
return getUpdatedTime(threadName) - startTimes.get(threadName);
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
String threadName = threadNames.get(rowIndex);
switch(columnIndex) {
case 0 :
return threadName;
case 1 :
return formatTime(startTimes.get(threadName));
case 2 :
return formatTime(getUpdatedTime(threadName));
case 3 :
return getLastedTime(threadName);
default :
throw new IndexOutOfBoundsException();
}
}
@Override
public Class<?> getColumnClass(int columnIndex) {
switch(columnIndex) {
case 0 : return String.class;
case 1 : return String.class;
case 2 : return String.class;
case 3 : return Long.class;
default : throw new IndexOutOfBoundsException();
}
}
@Override
public String getColumnName(int columnIndex) {
switch(columnIndex) {
case 0 : return "Thread Name";
case 1 : return "Start Time";
case 2 : return "Updated Time";
case 3 : return "Lated Time In Milli-Seconds";
default : throw new IndexOutOfBoundsException();
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
}