Как лучше всего запустить редактор ячеек со списком, набрав в ячейке JTable? - PullRequest
1 голос
/ 24 октября 2011

Другими словами, я хочу, чтобы JTable раскрывал выпадающий список всякий раз, когда пользователь вводит ячейку, с которой связан редактор JComboBox (или любой другой редактор ячеек на основе JComboBox).

Ответы [ 2 ]

1 голос
/ 24 октября 2011

По сути, вы должны установить соответствующий слушатель на комбо и явно открыть всплывающее окно.Первым кандидатом на "подходящее" является AncestorListener, который вызывает отображение всплывающего окна в своем методе ancestorAdded.

К сожалению, это не вся история: работает, если свойство surrenderFocus таблицы имеет значение false.Если это правда, работает только для нередактируемых комбо.После некоторого копания причиной неработающей части оказывается внутренний перенос (из комбинированного списка в текстовое поле) после того, как всплывающее окно открывается ancestorListener.В этом случае нам нужен второй слушатель, который открывает всплывающее окно, как только редактор editComponent постоянно получает фокус.

Несколько слушателей обычно наступают друг другу на ноги, поэтому лучше не устанавливать их постоянно, а делать это при каждом вызове getEditorComp, и позволить им удалить себя, как только они отобразят всплывающее окно.Ниже приведен рабочий пример того, как это сделать, просто остерегайтесь: он не был официально протестирован!

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

}
0 голосов
/ 02 февраля 2015
    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));
...