简体   繁体   中英

Java Swing: Custom Cell Editor does not return most recent value

I have created a custom cell editor which is attached to one of my JTable columns. The editor has either a JComboBox or a JTextField as component. However, when I edit the value of the combo box manually and press "tab", the new - most recent - value is not attached to the JTable cell. Instead, the old value is replaced. (I have already implemented the "tab" behaviour with another code template but this works in general, because all other table cells are updated correctly)

The combo box, which causes the problem is set in "case C". If the user now selects the ITEM "Infinity", the value is successfully attached to the JTable. However, if the user manually enters a value in the JTable and presses "tab", the new value is thrown away and the old value is rendered again in the table. However, as a hotfix, if the user enters the value in the combobox, hits "ENTER" immediately after and THEN tabs, the value is written through jtable correctly!

My custom cell editor implementation looks as follow:

public class CustomCellEditor extends AbstractCellEditor implements TableCellEditor {

    JFrame mParent                  = null;
    JFrame mPopup                   = null;
    String className                = "";

    protected int clickCountToStart = 2;

    private TableCellEditor mEditor = null;
    private JComboBox mComboBox     = null;

    public CustomCellEditor(JFrame parent, String className, JComboBox comboBox) {
        mParent             = parent;
        mClassName          = className;
        mComboBox           = comboBox;
    }

    @Override
    public Component getTableCellEditorComponent(final JTable table, final Object value, final boolean isSelected, final int row, final int column) {

        if ( className.equals("case A") ) {

            mComboBox.setModel( new DefaultComboBoxModel(Constants.YES_NO_ARRAY) );
            mComboBox.setEditable(false);
            mEditor = new DefaultCellEditor(mComboBox);
        }
        else if ( className.equals("case B") ) {

            mComboBox.setModel( new DefaultComboBoxModel(Constants.LANG_ARRAY) );
            mComboBox.setEditable(false);
            mEditor = new DefaultCellEditor(mComboBox);
        }
        else if ( className.equals("case C") ) {

            // THIS is the case, when the Jcombobox become editable, so beside the pre-defined item "Constants.INFIINITY" any arbitrary input should be allowed!
            mComboBox.setModel ( new DefaultComboBoxModel(new String[]{Constants.INFINITY}) ) ;
            mComboBox.setEditable(true);
            mEditor = new DefaultCellEditor(mComboBox);
        }
        else {
            mEditor = new DefaultCellEditor(new JTextField());
        }

        return mEditor.getTableCellEditorComponent(table, value, isSelected, row, column);
    }

    /**
    * Returns true if <code>anEvent</code> is <b>not</b> a
    * <code>MouseEvent</code>.  Otherwise, it returns true
    * if the necessary number of clicks have occurred, and
    * returns false otherwise.
    *
    * @param   anEvent         the event
    * @return  true  if cell is ready for editing, false otherwise
    * @see #setClickCountToStart
    * @see #shouldSelectCell
    */
    @Override
    public boolean isCellEditable(EventObject anEvent) {
        if (anEvent instanceof MouseEvent) {
            return ((MouseEvent)anEvent).getClickCount() >= clickCountToStart;
        }
        return true;
    }

    @Override
    public Object getCellEditorValue() {
        if (mEditor != null) {

            return mEditor.getCellEditorValue();
        }
        return null;
    }

}

Does someone know what the reason could be that in case of "case C" i did not get the most reason value but the previous table value instead?

Thank you

Here is an example that allows you to use a different editor without creating a custom editor. It overrides the getCellEditor(...) method of JTable:

import java.awt.*;
import java.util.List;
import java.util.ArrayList;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;

public class TableComboBoxByRow extends JPanel
{
    List<String[]> editorData = new ArrayList<String[]>(3);

    public TableComboBoxByRow()
    {
        setLayout( new BorderLayout() );

        // Create the editorData to be used for each row

        editorData.add( new String[]{ "Red", "Blue", "Green" } );
        editorData.add( new String[]{ "Circle", "Square", "Triangle" } );
        editorData.add( new String[]{ "Apple", "Orange", "Banana" } );

        //  Create the table with default data

        Object[][] data =
        {
            {"Color", "Red"},
            {"Shape", "Square"},
            {"Fruit", "Banana"},
            {"Plain", "Text"}
        };
        String[] columnNames = {"Type","Value"};

        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        JTable table = new JTable(model)
        {
            //  Determine editor to be used by row
            public TableCellEditor getCellEditor(int row, int column)
            {
                int modelColumn = convertColumnIndexToModel( column );

                if (modelColumn == 1 && row < 3)
                {
                    JComboBox<String> comboBox1 = new JComboBox<String>( editorData.get(row));
                    return new DefaultCellEditor( comboBox1 );
                }
                else
                    return super.getCellEditor(row, column);
            }
        };

        JScrollPane scrollPane = new JScrollPane( table );
        add( scrollPane );

    }

    private static void createAndShowUI()
    {
        JFrame frame = new JFrame("Table Combo Box by Row");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add( new TableComboBoxByRow() );
        frame.setSize(200, 200);
        frame.setLocationByPlatform( true );
        frame.setVisible( true );
    }

    public static void main(String[] args)
    {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                createAndShowUI();
            }
        });
    }
}

Your logic would be different because you are basing the editor on the class of the data in the cell, but the basic concept can be the same.

你有尝试过吗?

table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM