我在使用自定义模型的已修改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
测试类:
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;
}
}
}