我想写一个非常简单的JTable。
用户可以通过输入有效的双精度来编辑单元格。如果用户输入无效(即输入字符串),我希望我的表丢弃无效输入,显示最后一个好输入,并向用户显示错误消息。
我还希望表中的数字格式如下: " ### ##%"
我该怎么做呢?
其他信息
我知道我需要做的事情,但我在连接点时遇到了麻烦。
例如,我知道为了使格式正确,我必须继承DefaultTableCellRenderer
但是我不确定我在getTableCellRendererComponent()
方法中确切需要什么。
我很确定我必须继承DefaultCellEditor
以使编辑和错误检查正常工作。虽然我已经阅读了很多不同的东西。我不确定检查有效输入的最佳位置。我还读过关于InputVerifier
的信息,我不确定如何使用它,或者我是否应该使用它。
关于这样的事情如何起作用的一个小例子,以及我必须扩展/覆盖的不同类/方法的简要说明对我有用。
谢谢
答案 0 :(得分:1)
我知道为了使格式正确,我必须继承DefaultTableCellRenderer但是我不确定我在getTableCellRendererComponent()方法中究竟需要什么。
请参阅Table Format Rendering以获取执行此操作的简便方法。此方法只是覆盖了渲染器的setValue(...)
方法。
我很确定我必须继承DefaultCellEditor以使编辑和错误检查正常工作。
以下是我在论坛上找到的一些旧代码,它创建了一个自定义的IntegerEditor。第一列使用默认的Integer编辑器,第二列使用自定义编辑器。
import java.awt.*;
import java.util.EventObject;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.text.*;
import java.text.*;
import java.awt.event.*;
public class TableIntegerEditor
{
static class IntegerEditor extends DefaultCellEditor
{
JFormattedTextField ftf;
NumberFormat integerFormat;
private Integer minimum, maximum;
private boolean DEBUG = false;
public IntegerEditor(int min, int max)
{
super(new JFormattedTextField());
setClickCountToStart(2);
ftf = (JFormattedTextField)getComponent();
ftf.setBorder(new LineBorder(Color.BLACK));
minimum = new Integer(min);
maximum = new Integer(max);
//Set up the editor for the integer cells.
integerFormat = NumberFormat.getIntegerInstance();
NumberFormatter intFormatter = new NumberFormatter(integerFormat);
intFormatter.setFormat(integerFormat);
intFormatter.setMinimum(minimum);
intFormatter.setMaximum(maximum);
ftf.setFormatterFactory(new DefaultFormatterFactory(intFormatter));
ftf.setValue(minimum);
ftf.setHorizontalAlignment(JTextField.TRAILING);
ftf.setFocusLostBehavior(JFormattedTextField.PERSIST);
//React when the user presses Enter while the editor is
//active. (Tab is handled as specified by
//JFormattedTextField's focusLostBehavior property.)
ftf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "check");
ftf.getActionMap().put("check", new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if (!ftf.isEditValid()) //The text is invalid.
{
if (userSaysRevert())
{
ftf.postActionEvent(); //inform the editor
}
}
else
try
{
ftf.commitEdit(); //so use it.
ftf.postActionEvent(); //stop editing
}
catch (java.text.ParseException exc) { }
}
});
}
@Override
public boolean isCellEditable(EventObject event)
{
JTable table = (JTable)event.getSource();
return true;
}
//Override to invoke setValue on the formatted text field.
public Component getTableCellEditorComponent(
JTable table, Object value, boolean isSelected, int row, int column)
{
JFormattedTextField ftf = (JFormattedTextField)super.getTableCellEditorComponent(
table, value, isSelected, row, column);
ftf.setValue(value);
return ftf;
}
//Override to ensure that the value remains an Integer.
public Object getCellEditorValue()
{
JFormattedTextField ftf = (JFormattedTextField)getComponent();
Object o = ftf.getValue();
if (o instanceof Integer)
{
return o;
}
else if (o instanceof Number)
{
return new Integer(((Number)o).intValue());
}
else
{
try
{
return integerFormat.parseObject(o.toString());
}
catch (ParseException exc)
{
System.err.println("getCellEditorValue: can't parse o: " + o);
return null;
}
}
}
//Override to check whether the edit is valid,
//setting the value if it is and complaining if
//it isn't. If it's OK for the editor to go
//away, we need to invoke the superclass's version
//of this method so that everything gets cleaned up.
public boolean stopCellEditing()
{
JFormattedTextField ftf = (JFormattedTextField)getComponent();
if (ftf.isEditValid())
{
try
{
ftf.commitEdit();
}
catch (java.text.ParseException exc) { }
}
else
{
if (!userSaysRevert()) //user wants to edit
{
return false; //don't let the editor go away
}
}
return super.stopCellEditing();
}
/**
* Lets the user know that the text they entered is
* bad. Returns true if the user elects to revert to
* the last good value. Otherwise, returns false,
* indicating that the user wants to continue editing.
*/
protected boolean userSaysRevert() {
Toolkit.getDefaultToolkit().beep();
ftf.selectAll();
Object[] options = {"Edit",
"Revert"};
int answer = JOptionPane.showOptionDialog(
SwingUtilities.getWindowAncestor(ftf),
"The value must be an integer between "
+ minimum + " and "
+ maximum + ".\n"
+ "You can either continue editing "
+ "or revert to the last valid value.",
"Invalid Text Entered",
JOptionPane.YES_NO_OPTION,
JOptionPane.ERROR_MESSAGE,
null,
options,
options[1]);
if (answer == 1) { //Revert!
ftf.setValue(ftf.getValue());
return true;
}
return false;
}
}
private static void createAndShowGUI()
{
String[] columnNames = {"String", "Integer", "Integer2"};
Object[][] data =
{
{"a", new Integer(1), new Integer(10)},
{"b", new Integer(2), new Integer(20)},
{"c", new Integer(3), new Integer(30)}
};
JTable table = new JTable(data, columnNames)
{
public Class getColumnClass(int column)
{
if (column == 0)
return String.class;
else
return Integer.class;
}
};
table.setPreferredScrollableViewportSize(table.getPreferredSize());
JScrollPane scrollPane = new JScrollPane( table );
table.getColumnModel().getColumn(2).setCellEditor( new IntegerEditor(0, 200) );
DefaultCellEditor editor = (DefaultCellEditor)table.getDefaultEditor(Integer.class);
JComponent border = (JComponent)editor.getComponent();
border.setBorder( BorderFactory.createLineBorder( Color.RED ) );
JFrame frame = new JFrame("Integer Editor");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( scrollPane );
frame.setLocationByPlatform( true );
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
}
}
如果您只想使用默认的Double编辑器,那么您只需要将列类更改为列的Double.class。如果您需要特殊编辑,那么您需要根据双重要求自定义IntegerEditor。