0

I have a JTable that uses a custom TableModel. I extended the AbstractCellEditor class and the cell correctly displays the text typed in to the textfield when I double-click the textfield. but when I just single-click select the cell in the table and start typing, the textfield receives the text but when I press enter, it doesn't update the text field. I attached a focus listener to the textfield to troubleshoot and found that it only gains and loses focus when I double click on the field. With a single-click it doesn't gain focus (even though it allows me to edit it). This boggles my mind! I've tried textField.grabFocus(), textField.requestFocusInWindow(), and all sorts of other things. Any suggestions? Thanks!

public class IndexerCellEditor extends AbstractCellEditor implements
    TableCellEditor {
private JTextField textField;
private RecordValue currentValue;

public IndexerCellEditor(){
    textField = new JTextField();
}

@Override
public boolean isCellEditable(EventObject e){
    if(e instanceof MouseEvent){
        return ((MouseEvent)e).getClickCount() >= 2;
    }

    return true;
}


@Override
public Object getCellEditorValue() {
    return currentValue;
}


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

    textField.setBorder(BorderFactory.createLineBorder(Color.black, 1));

    currentValue = (RecordValue) value;

    textField.setText(currentValue.getValue());

    textField.addFocusListener(new FocusListener(){

        @Override
        public void focusGained(FocusEvent e) {
            System.out.println("focus gained");

        }

        @Override
        public void focusLost(FocusEvent e) {
            System.out.println("focus lost");

        }

    });

    textField.addActionListener(new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent e) {

            currentValue.setValue(((JTextField)e.getSource()).getText());

            fireEditingStopped();
        }
    });

    return textField;
}

}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
ejsuncy
  • 419
  • 1
  • 4
  • 13
  • For comparison, see this complete [example](http://stackoverflow.com/a/10067560/230513). – trashgod Aug 10 '13 at 18:20
  • 1
    because private RecordValue currentValue; has wrong parameter (overload), in line 45th. – mKorbel Aug 10 '13 at 18:27
  • @mKorbel anonymous inner classes have access to the private variables (currentValue) of their outer class. Besides, the above code works correctly when I DOUBLE CLICK on the cell (see `isCellEditable()` method). I just don't know why the actionevent isn't fired when I single click and start typing, then press `enter`. – ejsuncy Aug 10 '13 at 19:00

1 Answers1

-1

OK so after about 8 more hours of banging my head against the wall, I found out 2 things:

  1. I don't need an action listener on the jtextfield because the JTable takes care of that for me. When I hit enter after double clicking + typing OR single-click + typing, JTable automatically calls stopCellEditing(), which brings me to

  2. I need to override stopCellEditing() in my IndexerCellEditor class to save the JTextField text before passing it up to the parent. The code I was missing:

    @Override
    public boolean stopCellEditing(){
            currentValue = textField.getText();
            return super.stopCellEditing();
    }
    

Hope this helps anyone with the same problem.

EDIT This works in my case because I also extended DefaultTableModel, which takes care of notifying the listeners with the method:

@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
    cells[rowIndex][columnIndex] = (String) aValue;
    fireTableCellUpdated(rowIndex, columnIndex);
}

I tested this some more by building two different tables with the same extended DefaultTableModel. Placing them side-by-side in a JPanel, I could edit one cell in one table and upon pressing enter, it would update both the edited cell and its counterpart cell in the other table. In short, the listeners DO need to be notified with a fire... method call somewhere in the project.

ejsuncy
  • 419
  • 1
  • 4
  • 13
  • 1
    your bullet 1. is _wrong_ - if you don't implement the editor to notify its listeners on terminating edits, the implementation is invalid. Don't add the actionListener in getXX, instead do so in the contructor And beware: focus is a brittle property in editors (a JTable has this infamous editing mode where the table keeps focus and routes the keyEvents via processKeyBinding) – kleopatra Aug 10 '13 at 21:49
  • that last part of bullet 1 (`which brings me to`) implies that 1 and 2 are to be used in conjunction. I completely removed the action listener from my textfield, but I override `stopCellEditing()`. see #2 - I let the superclass take care of the notifying with `super.stopCellEditing()`. It works just fine now. – ejsuncy Aug 11 '13 at 19:05
  • super only takes care of the _mechanics_ of notification - it's the responsibility of the concrete subclass to actually _use_ the mechanics. Repeating: cellEditors (same as any valid implementation of some api) _must comply_ to its contract (vs. relying on some other class accidentally being lenient in certain contexts) – kleopatra Aug 12 '13 at 11:41
  • Sorry- I didn't specify the scope of this project--I also extended `DefaultTableModel`, which the table is built on and takes care of notifying. See edit. – ejsuncy Aug 13 '13 at 16:21
  • editor and model are unrelated ... the latter _cannot_ take care of notifying the _editor's_ listeners – kleopatra Aug 14 '13 at 08:21