Java JComboBox内JTable开始单元格编辑延迟
我正在使用Java JComboBox内JTable开始单元格编辑延迟,java,swing,jcombobox,tablecelleditor,Java,Swing,Jcombobox,Tablecelleditor,我正在使用JXComboBox作为自定义模型的修改JXTable/RXTable中的单元格编辑器。我注意到在单元格内开始打字时出现延迟 编辑:此外,如果您在框中键入更多键的速度更快,则您键入的第一个键将不会首先出现在编辑器中 下表: import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; import javax.swing.table.*; import javax.swing.
JXComboBox
作为自定义模型的修改JXTable
/RXTable
中的单元格编辑器。我注意到在单元格内开始打字时出现延迟
编辑:此外,如果您在框中键入更多键的速度更快,则您键入的第一个键将不会首先出现在编辑器中
下表:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import javax.swing.text.*;
import org.jdesktop.swingx.JXTable;
/**
* This is a modified version of RXTable following this thread:
* http://stackoverflow.com/questions/7365397/combining-jxtable-with-rxtable.
* The JRXTable provides some extensions to the default JTable
*
* 1) Select All editing - when a text related cell is placed in editing mode
* the text is selected. Controlled by invoking a "setSelectAll..." method.
*
* 2) reorderColumns - static convenience method for reodering table columns
*/
public class JRXTable extends JXTable {
private boolean isSelectAllForMouseEvent = false;
private boolean isSelectAllForActionEvent = false;
private boolean isSelectAllForKeyEvent = false;
//
// Constructors
//
/**
* Constructs a default
* <code>JRXTable</code> that is initialized with a default data model, a
* default column model, and a default selection model.
*/
public JRXTable() {
this(null, null, null);
}
/**
* Constructs a
* <code>JRXTable</code> that is initialized with
* <code>dm</code> as the data model, a default column model, and a default
* selection model.
*
* @param dm the data model for the table
*/
public JRXTable(TableModel dm) {
this(dm, null, null);
}
/**
* Constructs a
* <code>JRXTable</code> that is initialized with
* <code>dm</code> as the data model,
* <code>cm</code> as the column model, and a default selection model.
*
* @param dm the data model for the table
* @param cm the column model for the table
*/
public JRXTable(TableModel dm, TableColumnModel cm) {
this(dm, cm, null);
}
/**
* Constructs a
* <code>JRXTable</code> that is initialized with
* <code>dm</code> as the data model,
* <code>cm</code> as the column model, and
* <code>sm</code> as the selection model. If any of the parameters are
* <code>null</code> this method will initialize the table with the
* corresponding default model. The
* <code>autoCreateColumnsFromModel</code> flag is set to false if
* <code>cm</code> is non-null, otherwise it is set to true and the column
* model is populated with suitable
* <code>TableColumns</code> for the columns in
* <code>dm</code>.
*
* @param dm the data model for the table
* @param cm the column model for the table
* @param sm the row selection model for the table
*/
public JRXTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
super(dm, cm, sm);
}
/**
* Constructs a
* <code>JRXTable</code> with
* <code>numRows</code> and
* <code>numColumns</code> of empty cells using
* <code>DefaultTableModel</code>. The columns will have names of the form
* "A", "B", "C", etc.
*
* @param numRows the number of rows the table holds
* @param numColumns the number of columns the table holds
*/
public JRXTable(int numRows, int numColumns) {
this(new DefaultTableModel(numRows, numColumns));
}
/**
* Constructs a
* <code>JRXTable</code> to display the values in the
* <code>Vector</code> of
* <code>Vectors</code>,
* <code>rowData</code>, with column names,
* <code>columnNames</code>. The
* <code>Vectors</code> contained in
* <code>rowData</code> should contain the values for that row. In other
* words, the value of the cell at row 1, column 5 can be obtained with the
* following code:
* <p>
* <pre>((Vector)rowData.elementAt(1)).elementAt(5);</pre>
* <p>
*
* @param rowData the data for the new table
* @param columnNames names of each column
*/
public JRXTable(Vector rowData, Vector columnNames) {
this(new DefaultTableModel(rowData, columnNames));
}
/**
* Constructs a
* <code>JRXTable</code> to display the values in the two dimensional array,
* <code>rowData</code>, with column names,
* <code>columnNames</code>.
* <code>rowData</code> is an array of rows, so the value of the cell at row
* 1, column 5 can be obtained with the following code:
* <p>
* <pre> rowData[1][5]; </pre>
* <p>
* All rows must be of the same length as
* <code>columnNames</code>.
* <p>
*
* @param rowData the data for the new table
* @param columnNames names of each column
*/
public JRXTable(final Object[][] rowData, final Object[] columnNames) {
super(rowData, columnNames);
}
//
// Overridden methods
//
/*
* Override to provide Select All editing functionality
*/
@Override
public boolean editCellAt(int row, int column, EventObject e) {
boolean result = super.editCellAt(row, column, e);
// my editing
//
// if (e instanceof KeyEvent && isSelectAllForKeyEvent) {
// KeyEvent keyEvent = (KeyEvent) e;
// Character keyChar = keyEvent.getKeyChar();
// if (keyChar == KeyEvent.VK_ESCAPE) {
// return result;
// }
// }
// my editing
if (isSelectAllForMouseEvent
|| isSelectAllForActionEvent
|| isSelectAllForKeyEvent) {
selectAll(e);
}
return result;
}
/*
* Select the text when editing on a text related cell is started
*/
private void selectAll(EventObject e) {
final Component editor = getEditorComponent();
// add suport for the text editor from a ComboBox
// move to editCellAt method?
if (getEditorComponent() instanceof JComboBox) {
final JComboBox combo = (JComboBox) getEditorComponent();
ComboBoxEditor comboEditor = combo.getEditor();
final JTextField comboTextField = (JTextField) comboEditor.getEditorComponent();
// comboEditor.selectAll();
if (e instanceof KeyEvent && isSelectAllForKeyEvent) {
KeyEvent keyEvent = (KeyEvent) e;
final Character keyChar = keyEvent.getKeyChar();
if (keyChar == KeyEvent.VK_ESCAPE) {
System.out.println("escape");
// combo.getFocusCycleRootAncestor().requestFocus();
// combo.transferFocus();
} else {
comboEditor.selectAll();
comboTextField.setText(comboTextField.getText());
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
// set null value if the Delete key is pressed
if (keyChar == KeyEvent.VK_DELETE) {
combo.setSelectedItem(null);
comboTextField.setText(null);
} else {
comboTextField.selectAll();
// comboTextField.setText("");
}
}
});
}
}
return;
}
if (editor == null
|| !(editor instanceof JTextComponent
|| editor instanceof JFormattedTextField)) {
return;
}
if (e == null) {
((JTextComponent) editor).selectAll();
return;
}
// Typing in the cell was used to activate the editor
if (e instanceof KeyEvent && isSelectAllForKeyEvent) {
((JTextComponent) editor).selectAll();
return;
}
// If the cell we are dealing with is a JFormattedTextField
// force to commit, and invoke selectall
if (editor instanceof JFormattedTextField) {
invokeSelectAll((JFormattedTextField) editor);
return;
}
// F2 was used to activate the editor
if (e instanceof ActionEvent && isSelectAllForActionEvent) {
((JTextComponent) editor).selectAll();
return;
}
// A mouse click was used to activate the editor.
// Generally this is a double click and the second mouse click is
// passed to the editor which would remove the text selection unless
// we use the invokeLater()
if (e instanceof MouseEvent && isSelectAllForMouseEvent) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
((JTextComponent) editor).selectAll();
}
});
}
}
private void invokeSelectAll(final JFormattedTextField editor) {
// old trick: force to commit, and invoke selectall
editor.setText(editor.getText());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
editor.selectAll();
}
});
}
//
// Newly added methods
//
/*
* Sets the Select All property for for all event types
*/
public void setSelectAllForEdit(boolean isSelectAllForEdit) {
setSelectAllForMouseEvent(isSelectAllForEdit);
setSelectAllForActionEvent(isSelectAllForEdit);
setSelectAllForKeyEvent(isSelectAllForEdit);
}
/*
* Set the Select All property when editing is invoked by the mouse
*/
public void setSelectAllForMouseEvent(boolean isSelectAllForMouseEvent) {
this.isSelectAllForMouseEvent = isSelectAllForMouseEvent;
}
/*
* Set the Select All property when editing is invoked by the "F2" key
*/
public void setSelectAllForActionEvent(boolean isSelectAllForActionEvent) {
this.isSelectAllForActionEvent = isSelectAllForActionEvent;
}
/*
* Set the Select All property when editing is invoked by
* typing directly into the cell
*/
public void setSelectAllForKeyEvent(boolean isSelectAllForKeyEvent) {
this.isSelectAllForKeyEvent = isSelectAllForKeyEvent;
}
//
// Static, convenience methods
//
/**
* Convenience method to order the table columns of a table. The columns are
* ordered based on the column names specified in the array. If the column
* name is not found then no column is moved. This means you can specify a
* null value to preserve the current order of a given column.
*
* @param table the table containing the columns to be sorted
* @param columnNames an array containing the column names in the order they
* should be displayed
*/
public static void reorderColumns(JTable table, Object... columnNames) {
TableColumnModel model = table.getColumnModel();
for (int newIndex = 0; newIndex < columnNames.length; newIndex++) {
try {
Object columnName = columnNames[newIndex];
int index = model.getColumnIndex(columnName);
model.moveColumn(index, newIndex);
} catch (IllegalArgumentException e) {
}
}
}
} // End of Class JRXTable
*
*
*@param rowData新表的数据
*@param columnNames每列的名称
*/
公共JRXTable(向量行数据、向量列名称){
这个(新的DefaultTableModel(rowData,columnNames));
}
/**
*构建一个
*JRXTable
要在二维数组中显示值,
*rowData
,带有列名,
*列名称
。
*rowData
是一个行数组,因此第行的单元格值
*1,第5列可通过以下代码获得:
*
*
测试类:
导入java.text.FieldPosition;
导入java.text.Format;
导入java.text.ParsePosition;
导入java.util.HashMap;
导入javax.swing.ComboBoxEditor;
导入javax.swing.DefaultComboxModel;
导入javax.swing.JComponent;
导入javax.swing.JFrame;
导入javax.swing.JScrollPane;
导入javax.swing.JTabbedPane;
导入javax.swing.plaf.basic.BasicComboxeditor;
导入javax.swing.table.DefaultTableModel;
导入org.jdesktop.swingx.JXComboBox;
导入org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
导入org.jdesktop.swingx.autocomplete.ComboBoxCellEditor;
导入org.jdesktop.swingx.autocomplete.objecttoString转换器;
导入org.jdesktop.swingx.renderer.DefaultListRenderer;
导入org.jdesktop.swingx.renderer.DefaultTableRenderer;
导入org.jdesktop.swingx.renderer.StringValue;
公共类TestSwingXComboCellEditor{
公共静态void main(字符串[]args){
TestSwingXComboCellEditor test=新的TestSwingXComboCellEditor();
test.go();
}
公开作废go(){
//创建框架
JFrame=新JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//创建选项卡式窗格并将其添加到框架中
JTabbedPane tabbedPane=新的JTabbedPane();
frame.getContentPane().add(选项卡窗格);
//创建表格并将其添加到新选项卡中的滚动窗格中
JRXTable table=新的JRXTable();
setModel(新的DefaultTableModel(新对象[]{“A”,“B”},5));
表.setSelectalForEdit(真);
JScrollPane scrollPane=新的JScrollPane(表);
addTab(“测试”,滚动窗格);
//创建一个简单的JComboBox,并将其设置为列a上的表格单元编辑器
UserRepository=newuserrepository();
UserInfo[]comboElements=rep.getAllUsers();
DefaultComboxModel=新的DefaultComboxModel(comboElements);
JXComboBox组合框=新的JXComboBox(型号);
StringValue StringValue=新StringValue(){
公共字符串getString(对象值){
if(UserInfo的值instanceof){
UserInfo UserInfo=(UserInfo)值;
返回userInfo.getFirstName();
}否则{
返回“”;
}
}
};
ComboBoxCellEditor cellEditor=新建ComboxCellEditor(comboBox);
setRenderer(新的DefaultListRenderer(stringValue));
comboBox.setEditable(真);
装饰(组合框,新ObjectToStringConverter()){
@凌驾
公共字符串getPreferredStringForItem(对象项){
if(UserInfo的项目实例){
return((UserInfo)项).getFirstName();
}否则{
返回null;
}
}
});
table.getColumn(“A”).setCellEditor(cellEditor);
table.getColumn(“A”).setCellRenderer(新的DefaultTableRenderer(stringValue));
//包装展示架
frame.pack();
frame.setVisible(true);
}
公共类用户信息{
私有字符串名;
私有字符串lastName;
public UserInfo(String firstName、String lastName){
this.firstName=firstName;
this.lastName=lastName;
}
公共字符串getFirstName(){
返回名字;
}
公共字符串getLastName(){
返回姓氏;
}
}
公共类用户存储库{
UserInfo[]组合元素;
HashMap对象映射;
公共用户存储库(){
comboElements=新用户信息[5];
comboElements[0]=新用户信息(“John”、“Doe”);
comboElements[1]=新用户信息(“Betty”、“Doe”);
comboElements[2]=新用户信息(“Elenor”、“Smith”);
comboElements[3]=新用户信息(“Helen”、“Kelly”);
comboElements[4]=新用户信息(“Joe”、“Black”);
objectsMap=newHashMap();
对于(int i=0;i<5;i++){
objectsMap.put(comboElements[i].getFirstName(),comboElements[i]);
}
}
public UserInfo getUserInfo(字符串名称){
返回objectsMap.get(名称);
}
公共用户信息[]getAllUsers(){
返回组合元素;
}
}
}
ehh。。。那不是SSCCE,是吗;-)甚至尝试过但放弃了使用glazedList autocomplete——这不是我的地盘(混合太多非标准组件通常是个坏主意),我没有在这里使用glazedList
。只是我试过的其他东西的残留物。我现在就把它拿走了,很抱歉。我试着把它说得尽可能简单,但无法复制其他行为。有3个类:JRXTable
,它是一个修改的RXTable
,一个自定义的CellEditor
,以及包含main
的测试类。我相信问题出在世界的某个角落
import java.text.FieldPosition;
import java.text.Format;
import java.text.ParsePosition;
import java.util.HashMap;
import javax.swing.ComboBoxEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.plaf.basic.BasicComboBoxEditor;
import javax.swing.table.DefaultTableModel;
import org.jdesktop.swingx.JXComboBox;
import org.jdesktop.swingx.autocomplete.AutoCompleteDecorator;
import org.jdesktop.swingx.autocomplete.ComboBoxCellEditor;
import org.jdesktop.swingx.autocomplete.ObjectToStringConverter;
import org.jdesktop.swingx.renderer.DefaultListRenderer;
import org.jdesktop.swingx.renderer.DefaultTableRenderer;
import org.jdesktop.swingx.renderer.StringValue;
public class TestSwingXComboCellEditor {
public static void main(String[] args) {
TestSwingXComboCellEditor test = new TestSwingXComboCellEditor();
test.go();
}
public void go() {
//create the frame
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// create and add a tabbed pane to the frame
JTabbedPane tabbedPane = new JTabbedPane();
frame.getContentPane().add(tabbedPane);
//create a table and add it to a scroll pane in a new tab
JRXTable table = new JRXTable();
table.setModel(new DefaultTableModel(new Object[]{"A", "B"}, 5));
table.setSelectAllForEdit(true);
JScrollPane scrollPane = new JScrollPane(table);
tabbedPane.addTab("test", scrollPane);
// create a simple JComboBox and set is as table cell editor on column A
UserRepository rep = new UserRepository();
UserInfo[] comboElements = rep.getAllUsers();
DefaultComboBoxModel model = new DefaultComboBoxModel(comboElements);
JXComboBox comboBox = new JXComboBox(model);
StringValue stringValue = new StringValue() {
public String getString(Object value) {
if (value instanceof UserInfo) {
UserInfo userInfo = (UserInfo) value;
return userInfo.getFirstName();
} else {
return "";
}
}
};
ComboBoxCellEditor cellEditor = new ComboBoxCellEditor(comboBox);
comboBox.setRenderer(new DefaultListRenderer(stringValue));
comboBox.setEditable(true);
AutoCompleteDecorator.decorate(comboBox, new ObjectToStringConverter() {
@Override
public String getPreferredStringForItem(Object item) {
if (item instanceof UserInfo) {
return ((UserInfo) item).getFirstName();
} else {
return null;
}
}
});
table.getColumn("A").setCellEditor(cellEditor);
table.getColumn("A").setCellRenderer(new DefaultTableRenderer(stringValue));
// pack and show frame
frame.pack();
frame.setVisible(true);
}
public class UserInfo {
private String firstName;
private String lastName;
public UserInfo(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
}
public class UserRepository {
UserInfo[] comboElements;
HashMap<String, UserInfo> objectsMap;
public UserRepository() {
comboElements = new UserInfo[5];
comboElements[0] = new UserInfo("John", "Doe");
comboElements[1] = new UserInfo("Betty", "Doe");
comboElements[2] = new UserInfo("Elenor", "Smith");
comboElements[3] = new UserInfo("Helen", "Kelly");
comboElements[4] = new UserInfo("Joe", "Black");
objectsMap = new HashMap<>();
for (int i = 0; i < 5; i++) {
objectsMap.put(comboElements[i].getFirstName(), comboElements[i]);
}
}
public UserInfo getUserInfo(String name) {
return objectsMap.get(name);
}
public UserInfo[] getAllUsers() {
return comboElements;
}
}
}