3

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

mKorbel
  • 109,525
  • 20
  • 134
  • 319
allegroBegin
  • 115
  • 1
  • 10
  • 1
    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 Jan 07 '14 at 21:50
  • 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 Jan 07 '14 at 22:10
  • 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 Jan 07 '14 at 22:21
  • 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 Jan 08 '14 at 12:56
  • You have to put @MadProgrammer then he get notified. – nachokk Jan 08 '14 at 13:15
  • _you make a modification, everything needs to update_ that's the task of the model .. – kleopatra Jan 08 '14 at 15:38
  • @allegroBegin That's may point. Either do your updates within the model (using setValueAt) or use a model listener. Overriding a `JTable` is not recommended, ties you into a single implementation, can interfere with a known work flow and is generally an anti pattern and bad design... – MadProgrammer Jan 08 '14 at 20:19

3 Answers3

4

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

Community
  • 1
  • 1
nachokk
  • 14,363
  • 4
  • 24
  • 53
3

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


mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • More [here](http://stackoverflow.com/a/9095442/230513) on a suitable key binding. – trashgod Jan 07 '14 at 22:31
  • thank you for all the advices, I couldn't have posted any useful SSCCE as I have nothing really in there which would show what my issue was other then a keylistener on a jtable. I appreciate your links, I have read on custom renderers but it can't hurt to read more – allegroBegin Jan 07 '14 at 23:17
1

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.

tenorsax
  • 21,123
  • 9
  • 60
  • 107
  • 2
    -1 `Application code will not use these methods explicitly, they are used internally by JTable.` I think you should implement a `CellEditorListener` – nachokk Jan 07 '14 at 22:45
  • the CellEditorListener did not work at all, probably my fault, however, the way Aqua suggested worked perfectly, thank you, a days work finally with something to show for it public void editingStopped(ChangeEvent e) { calculateThings(); } – allegroBegin Jan 07 '14 at 23:14
  • 2
    @nachokk is right; if you can't use a key binding, an alternative is suggested [here](http://stackoverflow.com/a/13541516/230513). – trashgod Jan 08 '14 at 06:24
  • btw table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE); with success for standard JComponets – mKorbel Jan 08 '14 at 09:17
  • 1
    @allegroBegin if this is a solution, you are most probably fighting the winds of swing - re-visit your design would be the best advise I could give ;-) -1 for for suggesting a nuclear weapon – kleopatra Jan 08 '14 at 11:32
  • trashgod, I looked at all of your answers about this topic before I asked (you kept coming up on google) but nothing that I found, here or on any other community worked with the way I did things, I am happy to learn new things for other programs I may make, but this works very well and very fast, I really don't see what the problem is with it, @kleopatra, I see you're a self proclaimed expert in swing and I do not question that, but could you be a bit more explicit at in your tip about revisiting my design instead of using something which to me seems perfectly fine?Like why not,what else,etc – allegroBegin Jan 08 '14 at 13:01
  • 1
    @allegroBegin well , if you override `JTable#editingStopped` if you read the link it says by oracle's guys that that method is used by JTable internally, `Application code will not use these method explicity` if you decided to override it then you have to call `super.editingStopped` what is a bad design, and perhaps that method is call internally sometimes when you don't want to get called ;).. – nachokk Jan 08 '14 at 13:07
  • @allegroBegin: I'd go with a key binding, outlined [here](http://stackoverflow.com/a/9095442/230513), instead of a key listener; Aqua: +1 for `CellEditorListener`, left over from a hasty reading of the original answer. – trashgod Jan 08 '14 at 19:08
  • 1
    It would be better to use `TableModel#setValueAt` or implement a `TableModel` listener. Overriding the table in this manner is a bad design and anti pattern. Because the table may be using multiple editors, this also means you don't need to worry about trying to cover all possibilities...IMHO – MadProgrammer Jan 08 '14 at 20:22
  • @MadProgrammer agree, `TableModelListener` is cleaner, edited :) – tenorsax Jan 08 '14 at 22:04
  • the problem is ill-defined - my guess is that @allegroBegin is doing something fairly off the recommended approaches: it's definitely model's own business (vs. a listener's) to keep its internal state updated if anything is changed, f.i. by editing or other reasons. The issue with a particular key (and its different behaviour with/out editing) smells more like a problem with an assumed (incorrect) solution than with the _real_ requirement. Without knowing this, the question is not answerable, so voted to close. – kleopatra Jan 08 '14 at 23:23
  • 1
    Ok, I used cellEditorListener, it also works, I still think Aqua gave the best answers, not only for me but for anyone who looks for this, and I also see this question as closed. – allegroBegin Jan 10 '14 at 15:52