3
votes

I have a keylistener on jtable so that when someone presses enter some calculations happen. However, this only happens if the person is not editing. I would like to apply this action when a person finishes editing a cell and is pressing enter to finish and close the editing.

I cannot figure this out, anyone ever did this or know how to?

Basically, now for the action to be done, people must press enter twice, one to end the editing and another for the action that I want to happen, I would like to make it needed only once, while editing.

Thank you

3
KeyListener is probably not your friend, it rarely is. When a cell is updated, the models setValueAt method is called, which might be the best choice for getting the updates. If that's to much work. This should trigger a table model event, which you could also react to... - MadProgrammer
is prolly a good idea but I can't pull it off, I overrid the original, but it basically becomes a loop since I do setValue it calls a method which calculates and then again uses setValue and so on and so on until it becomes a stackoverflow. - allegroBegin
Personally, I would have a button called "refresh" (for example) and a key binding (perhaps F5) which was responsible for updating the calculations and updating the state of the model. The intention here is to disassociate the "calculation" from the model and table...but that's just me ;) - MadProgrammer
MadProgrammer, yes that's an overly simple idea(which I would use for myself as well), but unusable by normal users who want to do things fast and easy (trust me, I've had so many problems with these people) basically, the whole thing has to act just like excel, you make a modification, everything needs to update, no button pressing no nothing, that is why, editingStopped works perfectly here - allegroBegin
You have to put @MadProgrammer then he get notified. - nachokk

3 Answers

1
votes

You can override JTable.editingStopped, which is invoked when editing is finished and apply your actions in that method.

EDIT:

JTable.editingStopped was not designed for application extension. To avoid complications, in particular platform dependent ones, a better approach is to override model's setValueAt or register a TableModelListener. Here is an example:

import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

public class DemoTable3 {
    private static void createAndShowUI() {
        JFrame frame = new JFrame("DemoTable");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Object[][] rows = { { "Column 1", "Column 2" },
                { "Column 1", "Column 2" } };
        Object[] columns = { "Column 1", "Column 2" };

        DefaultTableModel model = new DefaultTableModel(rows, columns);
        model.addTableModelListener(new TableModelListener() {
            @Override
            public void tableChanged(TableModelEvent e) {
                System.out.println("apply additional action");
            }
        });

        JTable table = new JTable(model);
        frame.add(new JScrollPane(table));
        frame.setLocationByPlatform(true);
        frame.pack();
        frame.setVisible(true);
    }

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

Another alternative is to add CellEditorListener to catch editingStopped events. For example:

import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.DefaultTableModel;

public class DemoTable2 {

    private static void createAndShowUI() {
        JFrame frame = new JFrame("DemoTable");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Object[][] rows = { { "Column 1", "Column 2" },
                { "Column 1", "Column 2" } };
        Object[] columns = { "Column 1", "Column 2" };

        final JTable table = new JTable(new DefaultTableModel(rows, columns));

        table.getDefaultEditor(String.class).addCellEditorListener(
                new CellEditorListener() {
                    public void editingCanceled(ChangeEvent e) {
                        System.out.println("editingCanceled");
                    }

                    public void editingStopped(ChangeEvent e) {
                        System.out.println("editingStopped: apply additional action");
                    }
                });

        frame.add(new JScrollPane(table));
        frame.setLocationByPlatform(true);
        frame.pack();
        frame.setVisible(true);
    }

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

Also look at a Table Cell Listener by @camickr which offers custom processing of the edits.

4
votes

You could customize your own editor. Using DefaultCellEditor Instead using KeyListener you should use KeyBindings.

See this example.

            JTable table = new JTable(myModel);
            JTextField cell = new JTextField();
            final TableCellEditor cellEditor = new DefaultCellEditor(cell);
            table.getColumnModel().getColumn(column).setCellEditor(cellEditor);
            InputMap iMap = cell.getInputMap(JComponent.WHEN_FOCUSED);
            iMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),    KeyEvent.getKeyText(KeyEvent.VK_ENTER));
            ActionMap aMap = cell.getActionMap();
            aMap.put(KeyEvent.getKeyText(KeyEvent.VK_ENTER), new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if(callSomeOperationsIsOk()){
                      cellEditor.stopCellEditing();
                    }else{
                      cellEditor.cancelCellEditing();
                    }
                }
            });
    }

Read more in tutorials How to use Tables, and perhaps you have the same trouble that i have see my previous question

3
votes

I have a keylistener on jtable so that when someone presses enter some calculations happen. However, this only happens if the person is not editing. I would like to apply this action when a person finishes editing a cell and is pressing enter to finish and close the editing.

  • TableCellEditor hasn't something with KeyListener added to JTable

Basically, now for the action to be done, people must press enter twice, one to end the editing and another for the action that I want to happen, I would like to make it needed only once, while editing.

  • JComponents (used as TableCellEditor) by default to react to ENTER key pressed

  • don't to put JComponent to the TableModel, there should be stored only value painted by TableCellRenderer and initial value for TableCellEditor

  • TableCellEditor is temporarily JComponent, you have to add KeyBindings to invoke stopCellEditing in the case that JComponents used as TableCellEditor doesn't to react to ENTER key pressed