3

I need some help for my problem. I have a table with e.g. a double column and a string column. If the value in the double column is negativ, the string should be "negativ". And the other way if the value is positiv, the string should be "positiv". The problem is now if I edit the double value in the jTable, the string should also be updated.

Update to my question, the actual code look like this: But it doesn't work, because the string in the second column wont be updated after I edit the first column value. It only works when I start the program the first time.

import java.util.Vector;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.*;

public class ExampleRemoveAddRows extends JFrame {

    private Object[] columnNames = {"Double", "positiv / negativ"};
    private Object[][] data = {
        {new Double(10.0), "positiv"},
        {new Double(-10.0), "negativ"},
        {new Double(20.0), "positiv"},
        {new Double(-30.0), "negativ"}
    };
    private JTable table;
    private DefaultTableModel model;

    public ExampleRemoveAddRows() {
        model = new DefaultTableModel(data, columnNames) {
            @Override
            public Class getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }
            @Override
            public Object getValueAt(int row, int column) {  
                if (column == 1) {
                    double number = Double.parseDouble(this.getValueAt(row, 0).toString());
                    System.out.println(number);
                    System.out.println("good");
                    System.out.println((number < 0) ? "negativ" : "positiv");
                    return "C: "+ this.getValueAt(row, 0);//((number < 0) ? "negativ" : "positiv");
                } else {
                    return super.getValueAt(row, column);
                }
            }  
        };
        table = new JTable(model);        
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                ExampleRemoveAddRows frame = new ExampleRemoveAddRows();
                frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

Thanks for your help.

Sam

saduino
  • 65
  • 1
  • 5

2 Answers2

6

I've revised your sscce to show the alternate approach suggested here. Note the alternate ways to get a Double constant. I've also re-factored the String constrants.

Addendum: In helpful comments, @kleopatra observes that querying the model directly will always produce the correct result, but a TableModelListener will only see changes to column 0, not column 1. The simple expedient is to make column 1 non-editable, as its value depends completely on column 0.

@Override
public boolean isCellEditable(int row, int col) {
    return col == 0;
}

The first example below uses DefaultTableModel:

import javax.swing.*;
import javax.swing.table.*;

/** @see https://stackoverflow.com/a/13628183/230513 */
public class ExampleRemoveAddRows extends JFrame {

    public static final String NEGATIVE = "negativ";
    public static final String POSITIVE = "positiv";
    private Object[] columnNames = {"Double", POSITIVE + " / " + NEGATIVE};
    private Object[][] data = {
        {10d, null},
        {-10.0, null},
        {Double.valueOf(30), null},
        {Double.valueOf("-30"), null}
    };
    private JTable table;
    private DefaultTableModel model;

    public ExampleRemoveAddRows() {
        model = new DefaultTableModel(data, columnNames) {

            @Override
            public Class getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }

            @Override
            public boolean isCellEditable(int row, int col) {
                return col == 0;
            }

            @Override
            public Object getValueAt(int row, int col) {
                if (col == 1) {
                    double number = (Double) this.getValueAt(row, 0);
                    return (number < 0) ? NEGATIVE : POSITIVE;
                } else {
                    return super.getValueAt(row, col);
                }
            }

            @Override
            public void setValueAt(Object aValue, int row, int col) {
                super.setValueAt(aValue, row, col);
                fireTableCellUpdated(row, 1); // may have changed
            }
        };
        table = new JTable(model);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                ExampleRemoveAddRows frame = new ExampleRemoveAddRows();
                frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

This variation extends AbstractTableModel:

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

/**
* @see https://stackoverflow.com/a/13628183/230513
*/
public class ExampleRemoveAddRows extends JFrame {

    public static final String NEGATIVE = "negativ";
    public static final String POSITIVE = "positiv";

    public ExampleRemoveAddRows() {
        DoubleModel model = new DoubleModel();
        model.add(10.1);
        model.add(-10.2);
        model.add(Double.valueOf(30.1));
        model.add(Double.valueOf("-30.2"));
        JTable table = new JTable(model);
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane);
    }

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

            @Override
            public void run() {
                ExampleRemoveAddRows frame = new ExampleRemoveAddRows();
                frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    private class DoubleModel extends AbstractTableModel {

        List<Double> data = new ArrayList<Double>();

        public void add(Double d) {
            data.add(d);
        }

        @Override
        public int getRowCount() {
            return data.size();
        }

        @Override
        public int getColumnCount() {
            return 2;
        }

        @Override
        public String getColumnName(int col) {
            if (col == 0) {
                return "Double";
            } else {
                return POSITIVE + " / " + NEGATIVE;
            }
        }

        @Override
        public Class<?> getColumnClass(int col) {
            if (col == 0) {
                return Double.class;
            } else {
                return String.class;
            }
        }

        @Override
        public boolean isCellEditable(int row, int col) {
            return col == 0;
        }

        @Override
        public Object getValueAt(int row, int col) {
            if (col == 0) {
                return data.get(row);
            } else {
                double number = (Double) this.getValueAt(row, 0);
                return (number < 0) ? NEGATIVE : POSITIVE;
            }
        }

        @Override
        public void setValueAt(Object aValue, int row, int col) {
            if (col == 0) {
                data.set(row, (Double) aValue);
                fireTableRowsUpdated(row, row);
            }
        }
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 2
    ahhh, now I see what you meant :-) But that's not correct: when a change in the double column would result in a sign change (and as such the pos/neg column), the model fails to notify on changes in the pos/neg column ... – kleopatra Nov 29 '12 at 15:14
  • @kleopatra raises a critical point: querying the `TableModel` directly will always produce the correct result, but a `TableModelListener` will only see changes to column 0, not column 1. I've elaborated above. – trashgod Nov 29 '12 at 19:22
  • nice, but I'd be to use TableModelListener (event I deleted this post), I think that everything other only how to simulating this buil_in methods, hmmm (sure) maybe I'm wrong, – mKorbel Nov 30 '12 at 11:51
  • I would suggest you either remove or fix the DefaultTableModel extension in the example (because it's incorrect and errors tend to spread quickly :-) – kleopatra Nov 30 '12 at 11:53
  • @mKorbel don't quite understand what you are saying - but if it is something along the lines of the [other answer](http://stackoverflow.com/a/13612669/203657) (that is updating the model in a modelListener) then indeed you are wrong :-) – kleopatra Nov 30 '12 at 11:56
  • @mKorbel: I'd probably argue for a renderer; a second column has all the appeal of a de-normalized database. :-) – trashgod Nov 30 '12 at 12:04
  • @trashgod not :-) there aren't differencies betweens to determine whatever in setValueAt and event from TableModelListener, both are intenal notifiers in the same level of hierarchy, sure my view, then maybe I'm wrong, my bad, ("but I'm never ever have got any issue, aaach") – mKorbel Nov 30 '12 at 12:07
3

You do indeed have access to the TableModel, if I'm not mistaken, through TableModelEvent.getSource().

Just to provide a basic example (mostly because the one sentance answer hardly seems like much of an answer):

TableModel model = (TableModel)te.getSource();
Double number = model.getValueAt(te.firstRow, 0);
model.setValueAt(((number < 0) ? "negativ":"positiv"), te.firstRow, 1);
femtoRgon
  • 32,893
  • 7
  • 60
  • 87
  • The problem is solved, but I have a question. If you have more than one TableModel, which one do you get with `TableModel model = (TableModel)te.getSource();` ? – saduino Nov 28 '12 at 19:41
  • 2
    @saduino honestly using a TableModelListener does not seem like a good pattern. I would rather override setValueAt(int,int) on the table model and rather act in that method. In the end, this is what a model is for, not a table listener. – Guillaume Polet Nov 28 '12 at 19:44
  • @saduino getSource() will return "The object on which the Event initially occurred." (per [EventObject Documentation](http://docs.oracle.com/javase/1.4.2/docs/api/java/util/EventObject.html#getSource()) – femtoRgon Nov 28 '12 at 20:03
  • @GuillaumePolet, thanks for your hint, you are right. I solved it now with the `setValueAt(int,int)` method. – saduino Nov 28 '12 at 20:07
  • 1
    @saduino trashgod's solution is even better. Override getValueAt(int, int) and return the appropriate value for the column "negativ/positiv" based on the value found in the other column. – Guillaume Polet Nov 29 '12 at 08:51
  • 1
    saduino: @GuillaumePolet is right about using the model. For a purely dependent column like this, I'd follow the [example](http://stackoverflow.com/a/7356518/230513). – trashgod Nov 29 '12 at 12:52
  • @trashgod thanks for your example, I tried it, but it works only when I start the program. When I edit the value in column one then the column two will not update. Where is my fault? – saduino Nov 29 '12 at 13:35
  • I'm reluctant to hijack this Q&A. Why not pose a new question with your updated sscce? – trashgod Nov 29 '12 at 13:49
  • ehh ... no. As others already mentioned: a modelListener is for triggering dependent changes _outside_ the model. Taking care of internal dependencies is the exclusive task of the model itself. – kleopatra Nov 29 '12 at 14:14
  • @trashgod ok I updated my question above. Or should I open a new question? – saduino Nov 29 '12 at 14:24
  • I've shown the alternate approach [here](http://stackoverflow.com/a/13628183/230513). +1 to @femtoRgon for using the model – trashgod Nov 29 '12 at 14:43
  • thanks to trashgod for your example, it works now. In fact it worked already in my corrected code above, but only after the cell lose the selection. Sorry guys and thanks for your help. – saduino Nov 29 '12 at 14:59