通过键入JTable单元格来触发组合框单元格编辑器的最佳方法是什么?

时间:2011-10-24 09:23:35

标签: swing autocomplete jtable jcombobox swingx

换句话说,只要用户在具有与之关联的JComboBox(或任何其他基于JComboBox的单元格编辑器)编辑器的单元格中键入,我希望JTable下拉组合框。

2 个答案:

答案 0 :(得分:1)

基本上,您必须在组合上安装适当的侦听器并显式打开弹出窗口。 “适当”的第一个候选者是AncestorListener,它调用在其ancestorAdded方法中显示弹出窗口。

不幸的是,这似乎不是全部故事:如果表的surrenderFocus属性为false,则有效。如果它是真的只适用于不可编辑的组合。在进行了一些挖掘之后,在ancestorListener打开弹出窗口之后,无法工作部分的原因变成了内部focustransfer(从组合到文本字段)。在这种情况下,我们需要第二个监听器,一旦编辑器的editingComponent永久获得焦点,就会打开弹出窗口。

多个侦听器经常互相踩踏,所以最好不要永久安装,而是在每次调用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();
    }

}

答案 1 :(得分:0)

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