Reputation: 19797
In other words, I want JTable to drop-down a combo-box whenever user types in a cell that has a JComboBox (or any other JComboBox-based cell-editor) editor associated to it.
Upvotes: 1
Views: 1525
Reputation: 1
JTable table = new JTable(data, columns);
table.putClientProperty("terminateEditOnFocusLost", true);
JScrollPane scrollPane = new JScrollPane(table);
final JXComboBox editorComboBox = new JXComboBox(array);
editorComboBox.addAncestorListener(new AncestorListener() {
public void ancestorAdded(AncestorEvent event) {
//make sure combobox handles key events
editorComboBox.requestFocusInWindow();
}
public void ancestorMoved(AncestorEvent event) {}
public void ancestorRemoved(AncestorEvent event) {}
});
AutoCompleteDecorator.decorate(editorComboBox);
TableColumn column = table.getColumnModel().getColumn(0);
column.setCellEditor(new ComboBoxCellEditor(editorComboBox));
Upvotes: 0
Reputation: 51525
Basically, you have to install an appropriate listener on the combo and open the popup explicitly. First candidate for "appropriate" is an AncestorListener, which invokes showing the popup in its ancestorAdded method.
Unfortunately that doesn't seem to be the whole story: works if the table's surrenderFocus property is false. If it is true works only for not-editable combos. After some digging, the reason for the not-working part turns out to be an internal focustransfer (from the combo to the textfield) after the popup is opened by the ancestorListener. In that case, we need a second listener which opens the popup once the editor's editingComponent got the focus permanently.
Multiple listeners routinely step onto each other's feet, so best to not install both permanently but do it on each call to getEditorComp, and let them uninstall themselves once they showed the popup. Below is a working example of how-to do it, just beware: it's not formally tested!
public static class DefaultCellEditorX extends DefaultCellEditor {
private AncestorListener ancestorListener;
private PropertyChangeListener focusPropertyListener;
public DefaultCellEditorX(JComboBox comboBox) {
super(comboBox);
}
/**
* Overridden to install an appriate listener which opens the
* popup when actually starting an edit.
*
* @inherited <p>
*/
@Override
public Component getTableCellEditorComponent(JTable table,
Object value, boolean isSelected, int row, int column) {
super.getTableCellEditorComponent(table, value, isSelected, row, column);
installListener(table);
return getComponent();
}
/**
* Shows popup.
*/
protected void showPopup() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
getComponent().setPopupVisible(true);
}
});
}
/**
* Dynamically install self-uninstalling listener, depending on JComboBox
* and JTable state.
* @param table
*/
private void installListener(JTable table) {
if (getComponent().isEditable() && table.getSurrendersFocusOnKeystroke()) {
installKeyboardFocusListener();
} else {
installAncestorListener();
}
}
private void installAncestorListener() {
if (ancestorListener == null) {
ancestorListener = new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent event) {
getComponent().removeAncestorListener(ancestorListener);
showPopup();
}
@Override
public void ancestorRemoved(AncestorEvent event) {
}
@Override
public void ancestorMoved(AncestorEvent event) {
}
};
}
getComponent().addAncestorListener(ancestorListener);
}
private void installKeyboardFocusListener() {
if (focusPropertyListener == null) {
focusPropertyListener = new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
LOG.info("property: " + evt.getPropertyName());
if (focusManager().getPermanentFocusOwner() !=
getComponent().getEditor().getEditorComponent()) return;
focusManager()
.removePropertyChangeListener("permanentFocusOwner", focusPropertyListener);
showPopup();
}
};
}
focusManager().addPropertyChangeListener("permanentFocusOwner", focusPropertyListener);
}
/**
* Convience for less typing.
* @return
*/
protected KeyboardFocusManager focusManager() {
return KeyboardFocusManager.getCurrentKeyboardFocusManager();
}
/**
* Convenience for type cast.
* @inherited <p>
*/
@Override
public JComboBox getComponent() {
return (JComboBox) super.getComponent();
}
}
Upvotes: 1