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;
        }
    }

}