当尝试监视单元格编辑的开始和停止时,我发现了
DefaultCellEditor.EditorDelegate
类,其中包含有前途的方法 startCellEditing(EventObject anEvent)
。下面的代码的第一个版本没有
MouseListener
; startCellEditing(...)
从未被解雇。查看来源
说明了原因:该方法的单行内容为 return true
。fireEditingStarted()
方法不存在,所以我添加了 MouseListener
编辑器组件侦听编辑启动双击,然后调用 startCellEditing(...)
。但 MouseListener
也不会被解雇。startCellEditing(...)
继续下去呢?
附注:
我知道可以通过覆盖
JTable
来监视编辑的开始
prepareEditor(...)
,但我仍然想看看代码中缺少什么。
import java.awt.*;
import java.awt.event.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.table.*;
public class MonitorEditingStartStopped extends JFrame {
public MonitorEditingStartStopped() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(220, 150);
setLocationRelativeTo(null);
String headers[] = {"Fruit", "Count", "Profit"};
Object data[][] = {
{"Apple", 6, -0.3},
{"Banana", 3, 0.4},
{"Cherry", 10, 1.},
{"Date", -3, -1.}
};
DefaultTableModel model= new DefaultTableModel(headers, 0) {
public Class<?> getColumnClass(int column) {
Class<?> returnValue;
if (getRowCount()>0 && getValueAt(0, column)!=null)
returnValue= getValueAt(0, column).getClass();
else
returnValue= Object.class;
return returnValue;
}
};
for (int i=0; i<data.length; i++) {
model.addRow(data[i]);
}
JTable table= new JTable(model);
JTextField tf= new JTextField(10);
tf.setHorizontalAlignment(SwingConstants.RIGHT);
StartStopEditor editor= new StartStopEditor(table, tf);
TableColumnModel tcm= table.getColumnModel();
tcm.getColumn(1).setCellEditor(editor);
JScrollPane scrollPane= new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(MonitorEditingStartStopped::new);
}
class StartStopEditor extends DefaultCellEditor {
public StartStopEditor(JTable table, JTextField tf) {
super(tf);
delegate= new EditorDelegate() {
@Override
public Object getCellEditorValue() {
if (tf.getText().isBlank()) return Integer.valueOf(0);
return Integer.valueOf(tf.getText());
}
@Override
public boolean startCellEditing(EventObject anEvent) {
int row= table.getSelectedRow();
int column= table.getSelectedColumn();
System.out.println("started", row, column);
tf.setText(table.getValueAt(row, column).toString());
return true;
}
@Override
public boolean stopCellEditing() {
System.out.println("editing stopped", getCellEditorValue());
return super.stopCellEditing();
}
};
tf.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
System.out.println("Click");
if (e.getClickCount()!=2) return;
delegate.startCellEditing(new EventObject(tf));
}
});
}
}
}
按照 MadProgrammer 使用 JFormattedTextField 的想法,我想出了以下代码。
import java.awt.*;
import java.awt.event.*;
import java.text.*; // DecimalFormat, NumberFormat.
import java.util.EventObject;
import javax.swing.*;
import javax.swing.text.*; // NumberFormatter.
import javax.swing.table.*;
public class MonitorEditingStartStoppedFTF extends JFrame {
int row, column;
JFormattedTextField ftf;
public MonitorEditingStartStoppedFTF() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(220, 150);
setLocationRelativeTo(null);
String headers[] = {"Fruit", "Count", "Profit"};
Object data[][] = {
{"Apple", 6, -0.3},
{"Banana", 3, 0.4},
{"Cherry", 10, 1.},
{"Date", -3, -1.}
};
DefaultTableModel model= new DefaultTableModel(headers, 0) {
public Class<?> getColumnClass(int column) {
Class<?> returnValue;
if (getRowCount()>0 && getValueAt(0, column)!=null)
returnValue= getValueAt(0, column).getClass();
else
returnValue= Object.class;
return returnValue;
}
};
for (int i=0; i<data.length; i++)
model.addRow(data[i]);
JTable table= new JTable(model);
NumberFormatter numFmt = new NumberFormatter(new DecimalFormat("#,###"));
numFmt.setAllowsInvalid(false);
/* Even if ftf is made final, if ftf is not a class variable, the compiler
reports "variable ftf might not have been initialized" for the following two
System.out.println(... ftf.getValue()).
JFormattedTextField ftf= new JFormattedTextField(numFmt) {
*/
ftf= new JFormattedTextField(numFmt) {
@Override
protected void processFocusEvent(FocusEvent e) {
String s= e.paramString();
s= s.substring(0, s.indexOf(','));
if (s.equals("FOCUS_GAINED")) {
System.out.println("Editing starts "+ftf.getValue());
row= table.getSelectedRow();
column= table.getSelectedColumn();
System.out.printf("Row/column %d/%d value: %s%n", row, column,
table.getValueAt(row, column));
}
else if (s.equals("FOCUS_LOST")) {
System.out.println("Editing stopped "+ftf.getValue());
s= table.getValueAt(row, column).toString().replace(".", "");
System.out.printf("Row, column %d,%d value: %s%n%n", row, column, s);
table.setValueAt(Integer.valueOf(s), row, column);
ftf.setValue(Integer.valueOf(0));
}
super.processFocusEvent(e);
}
};
ftf.setHorizontalAlignment(SwingConstants.RIGHT);
DefaultCellEditor editor= new DefaultCellEditor(ftf);
TableColumnModel tcm= table.getColumnModel();
tcm.getColumn(1).setCellEditor(editor);
JScrollPane scrollPane= new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
setVisible(true);
}
public static void main(String args[]) {
EventQueue.invokeLater(MonitorEditingStartStoppedFTF::new);
}
}