在我的Java面板中,我有一个JTable
,其中两列通过自定义单元格编辑器使用包com.toedter.calendar中的JDateChooser
对象。与使用文本框或其他简单组件的单元格不同,您可以在不必事先单击单元格的情况下键入这些单元格,日期选择器单元格中不存在此功能。就我目前的理解而言,这是因为我的自定义编辑器返回JDateChooser
对象作为组件(通过getTableCellEditorComponent
方法)。由于JDateChooser
的父类是JPanel
(根据API),这就是它试图编辑的内容,当然,您不能在JPanel
中键入文本。当用户切换到日期选择器单元格并尝试在其中键入日期时,是否有某种方法可以检测?
附言:我确实找到了一种变通方法,请求将焦点放在日期选择器的文本字段上,但问题是你键入的第一个键没有出现在单元格中;它只是开始编辑单元格。如果可能的话,我希望它的行为,这样你就可以切换到单元格,例如,键入"1"一次,然后让"1"出现在其中,就像普通文本字段单元格一样。
显然,它在后来的版本中被删除了,API从未被删除已更改。
你说得对,我注意到API已经过时了,因为它是从1.2.1版本开始的,JCalendar的最新版本是1.4。我想他们没有时间更新API的在线版本,但随库分发的javadoc已经更新了。问题是getSpinner()不再可用,所以我之前的建议无法实现。
无论如何,我决定自己尝试使用JDateChooser
的DateCellEditor
,我没有遇到太多麻烦,只是我遇到了和你开始在单元格中键入时相同的行为。焦点似乎转移到了JDateChooser
顶级组件(正如您所说,它可能是JPanel
)。因此,我使用AncestorListener API将焦点转移到日期编辑器。@camicker在这篇文章中很好地解释了这种方法。
这就是我做的:
public class DateCellEditor extends AbstractCellEditor implements TableCellEditor {
JDateChooser editor;
public DateCellEditor() {
editor = new JDateChooser();
editor.setLocale(Locale.ENGLISH);
editor.setDateFormatString("MM/dd/yyyy");
editor.setFocusable(false); // Key #1
JComponent editorComponent = (JComponent)editor.getDateEditor();
editorComponent.addAncestorListener(new AncestorListener() { // Key #2
@Override
public void ancestorAdded(AncestorEvent event) {
((JComponent)editor.getDateEditor()).requestFocusInWindow();
}
@Override
public void ancestorRemoved(AncestorEvent event) {}
@Override
public void ancestorMoved(AncestorEvent event) {}
});
}
....
}
这里有两个关键因素:
- 使
editor
不可聚焦。这样可以避免焦点自动转移到作为其一部分的顶级容器 - 使用
AncestorListener
API
以下是完整的单元格编辑器实现:
import com.toedter.calendar.JDateChooser;
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import java.util.Locale;
import javax.swing.AbstractCellEditor;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.table.TableCellEditor;
public class DateCellEditor extends AbstractCellEditor implements TableCellEditor {
JDateChooser editor;
int clickCountToStart = 2;
public DateCellEditor() {
editor = new JDateChooser();
editor.setLocale(Locale.ENGLISH);
editor.setDateFormatString("MM/dd/yyyy");
editor.setFocusable(false);
JComponent editorComponent = (JComponent)editor.getDateEditor();
editorComponent.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent event) {
((JComponent)editor.getDateEditor()).requestFocusInWindow();
}
@Override
public void ancestorRemoved(AncestorEvent event) {}
@Override
public void ancestorMoved(AncestorEvent event) {}
});
}
@Override
public Object getCellEditorValue() {
return editor.getDate();
}
@Override
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart;
}
return true;
}
@Override
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
@Override
public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
@Override
public void cancelCellEditing() {
fireEditingCanceled();
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
if(value instanceof java.util.Date){
editor.setDate((java.util.Date)value);
table.setRowHeight((int)editor.getPreferredSize().getHeight());
//This last one is optional. It fits the row height to the JDateChooser preferred height.
}
return editor;
}
}
datepicker.getEditor().setEditable(true);