Java, изменить содержимое ячейки как функцию другой ячейки в той же строке

Мне нужна помощь в моей проблеме. У меня есть таблица, например. двойной столбец и строковый столбец. Если значение в двойном столбце отрицательное, строка должна быть отрицательной. И наоборот, если значение положительное, строка должна быть «положительной». Проблема в том, что теперь, если я редактирую двойное значение в jTable, строка также должна быть обновлена.

Обновите мой вопрос, фактический код выглядит так: Но это не работает, потому что строка во втором столбце не будет обновляться после того, как я отредактирую значение первого столбца. Это работает только при первом запуске программы.

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

Спасибо за вашу помощь.

Сэм


person saduino    schedule 28.11.2012    source источник


Ответы (2)


Я пересмотрел ваш sscce, чтобы показать альтернативный подход, предложенный здесь. Обратите внимание на альтернативные способы получения константы Double. Я также переработал константы String.

Приложение: в полезных комментариях @kleopatra отмечает, что прямой запрос к модели всегда будет давать правильный результат, но TableModelListener увидит изменения только в столбце 0, а не в столбце 1. Самый простой способ сделать столбец 1 не-редактируемый, так как его значение полностью зависит от столбца 0.

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

В первом примере ниже используется 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);
            }
        });
    }
}

Этот вариант 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);
            }
        }
    }
}
person trashgod    schedule 29.11.2012
comment
аааа, теперь я понимаю, что вы имели в виду :-) Но это неправильно: когда изменение в двойном столбце приведет к изменению знака (и, следовательно, в столбце pos/neg), модель не уведомляет об изменениях в pos /neg столбец ... - person kleopatra; 29.11.2012
comment
@kleopatra поднимает критическую точку: прямой запрос TableModel всегда будет давать правильный результат, но TableModelListener увидит изменения только в столбце 0, а не в столбце 1. Я подробно описал выше. - person trashgod; 29.11.2012
comment
хорошо, но я бы использовал TableModelListener (событие, я удалил этот пост), я думаю, что все остальное только как имитировать эти встроенные методы, хммм (конечно), может быть, я ошибаюсь, - person mKorbel; 30.11.2012
comment
Я бы посоветовал вам либо удалить, либо исправить расширение DefaultTableModel в примере (потому что оно неверно и ошибки быстро распространяются :-) - person kleopatra; 30.11.2012
comment
@mKorbel не совсем понимает, что вы говорите, но если это что-то вроде другого ответа (это обновляет модель в modelListener), тогда вы действительно ошибаетесь :-) - person kleopatra; 30.11.2012
comment
@mKorbel: я бы, наверное, поспорил за рендерер; второй столбец имеет всю привлекательность денормализованной базы данных. :-) - person trashgod; 30.11.2012
comment
@trashgod нет :-) нет различий между тем, чтобы определить что-либо в setValueAt и событием из TableModelListener, оба являются внутренними уведомителями на одном уровне иерархии, конечно, на мой взгляд, тогда, возможно, я ошибаюсь, мой плохой (но я У меня никогда не было проблем, аааа) - person mKorbel; 30.11.2012

У вас действительно есть доступ к TableModel, если я не ошибаюсь, через TableModelEvent.getSource().

Просто чтобы привести базовый пример (в основном потому, что ответ на одно предложение вряд ли кажется большим ответом):

TableModel model = (TableModel)te.getSource();
Double number = model.getValueAt(te.firstRow, 0);
model.setValueAt(((number < 0) ? "negativ":"positiv"), te.firstRow, 1);
person femtoRgon    schedule 28.11.2012
comment
Проблема решена, но у меня есть вопрос. Если у вас есть более одной TableModel, какую из них вы получите с TableModel model = (TableModel)te.getSource(); ? - person saduino; 28.11.2012
comment
@saduino, если честно, использовать TableModelListener не похоже на хороший шаблон. Я бы предпочел переопределить setValueAt(int,int) в модели таблицы и действовать в этом методе. В конце концов, именно для этого и нужна модель, а не табличный слушатель. - person Guillaume Polet; 28.11.2012
comment
@saduino getSource() вернет объект, на котором изначально произошло событие. (согласно документации EventObject - person femtoRgon; 29.11.2012
comment
@GuillaumePolet, спасибо за подсказку, вы правы. Я решил это сейчас с помощью метода setValueAt(int,int). - person saduino; 29.11.2012
comment
Решение @saduino trashgod даже лучше. Переопределите getValueAt(int, int) и верните соответствующее значение для отрицательного/положительного столбца на основе значения, найденного в другом столбце. - person Guillaume Polet; 29.11.2012
comment
@trashgod спасибо за пример, попробовал, но работает только при запуске программы. Когда я редактирую значение в первом столбце, второй столбец не будет обновляться. Где моя вина? - person saduino; 29.11.2012
comment
Я не хочу захватывать этот вопрос и ответ. Почему бы не задать новый вопрос с вашим обновленным sscce? - person trashgod; 29.11.2012
comment
эх... нет. Как уже упоминалось: modelListener предназначен для запуска зависимых изменений вне модели. Забота о внутренних зависимостях является исключительной задачей самой модели. - person kleopatra; 29.11.2012
comment
@trashgod хорошо, я обновил свой вопрос выше. Или мне открыть новый вопрос? - person saduino; 29.11.2012
comment
Я показал альтернативный подход здесь. +1 @femtoRgon за использование модели - person trashgod; 29.11.2012
comment
спасибо trashgod за ваш пример, теперь он работает. На самом деле это уже работало в моем исправленном коде выше, но только после того, как ячейка потеряла выделение. Извините, ребята, и спасибо за вашу помощь. - person saduino; 29.11.2012