Question

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

}
Was it helpful?

Solution

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top