Данные в JTable не меняются

Я слишком много пробовал и много читал. Все еще не мог найти никакого рабочего решения для моего случая. Итак, вот в чем дело. Во время игры деньги игроков меняются. Чего я пытаюсь добиться, так это мгновенно отображать деньги из JTable, чтобы игрок всегда мог следить за своими деньгами, просто глядя на стол. Но, как вы можете предположить, у меня не получилось поменять деньги, когда их меняют. Он просто остается на том уровне, с которого начал.

На данный момент я получил хорошо построенный JTable, который показывает начальные деньги игрока в начале и пользовательскую модель для моего JTable.

Поскольку я считаю, что решение зависит от модели и setValuesAt(Object value, int row, int column), я пытался найти выход. У меня есть метод под названием Refresh. Чтобы быть более конкретным, позвольте мне показать вам часть моего кода.

Итак, вот мой массив rowData в конструкторе, который я использую для отображения начальных денег в начале игры:

rowData = new Object[][]{
                {GameFlow.getPlayer1().getName(), "Pink", GameFlow.getPlayer1().getMoney()},
                {GameFlow.getPlayer2().getName(), "Blue", GameFlow.getPlayer2().getMoney()},
                {GameFlow.getPlayer3().getName(), "Green", GameFlow.getPlayer3().getMoney()},
                {GameFlow.getPlayer4().getName(), "Red", GameFlow.getPlayer4().getMoney()},
        };

Сказав это, я также должен показать вам эти две следующие функции, setValueAt и refresh (обновление — это метод, который я только что написал для простоты обновления изменений):

public void setValueAt(Object value, int row, int col) {
    rowData[row][col] = value;
    fireTableCellUpdated(row, col);
}
public void refresh(){
    for (int i = 0; i < 4; i++) {
        setValueAt(GameFlow.getPlayer1().getMoney(), i, 2);
    }
}

Здесь, при обновлении, я пытаюсь изменить только вторую (2-ю) строку, потому что первые две являются статичными и никогда не меняются. Кроме того, число 4 в цикле for — это количество игроков, поэтому 4 содержит количество строк.

Ниже вы можете найти весь код моей модели таблицы:

import javax.swing.table.AbstractTableModel;

public class MonopolyTableModel extends AbstractTableModel {
    private String[] columnNames = {
            "Name",
            "Color",
            "Money",
    };
    private Object[][] rowData;

    public MonopolyTableModel() {
        rowData = new Object[][]{
                {GameFlow.getPlayer1().getName(), "Pink", GameFlow.getPlayer1().getMoney()},
                {GameFlow.getPlayer2().getName(), "Blue", GameFlow.getPlayer2().getMoney()},
                {GameFlow.getPlayer3().getName(), "Green", GameFlow.getPlayer3().getMoney()},
                {GameFlow.getPlayer4().getName(), "Red", GameFlow.getPlayer4().getMoney()},
        };
    }
    @Override
    public int getRowCount() {
        return rowData.length; 
    }
    @Override
    public int getColumnCount() {
        return columnNames.length;
    }
    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        return rowData[rowIndex][columnIndex];
    }

    public void setValueAt(Object value, int row, int col) {
        rowData[row][col] = value;
        fireTableCellUpdated(row, col);
    }

    public String getColumnName(int columnIndex) {
        return columnNames[columnIndex];
    }

    public void refresh(){
        for (int i = 0; i < 4; i++) {
            setValueAt(GameFlow.getPlayer1().getMoney(), i, 2);
        }
    }

}

И вот как я использую в классе Gui:

MonopolyTableModel monoModel = (MonopolyTableModel) dataTable.getModel();
monoModel.refresh();

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


person Kutay Demireren    schedule 16.10.2015    source источник
comment
Рассмотрите возможность предоставления запускаемого примера, демонстрирующего вашу проблему. Это не дамп кода, а пример того, что вы делаете, который подчеркивает проблему, с которой вы столкнулись. Это приведет к меньшей путанице и лучшим ответам.   -  person MadProgrammer    schedule 16.10.2015
comment
Ваш метод setValueAt не имеет никакого отношения к фактическому объекту player, поэтому любые значения, которые вы изменяете в таблице, не повлияют на объект player.   -  person MadProgrammer    schedule 16.10.2015
comment
Деньги игрока меняются во время игры, я в этом уверен. Итак, setValueAt не имеет ничего общего со сменой игрока. Я просто не могу обновить таблицу. И, конечно же, я постараюсь дать больше кода для вашего удобства.   -  person Kutay Demireren    schedule 16.10.2015


Ответы (1)


Немного сложно понять, в чем может быть проблема, исходя из предоставленного вами внеконтекстного кода.

Всякий раз, когда я имею дело с JTable, я использую его для моделирования физических данных, в вашем случае это объект Player. Таким образом, если Player изменяется за пределами таблицы, вам просто нужно инициировать обновление модели, чтобы таблица обновила значения. Точно так же вы также можете централизовать некоторые функции в таблице и использовать ее для непосредственного изменения объекта Player.

Таким образом, модель и данные всегда синхронизированы (даже если отображение не синхронизировано).

В этом примере есть два способа обновить модель/таблицу.

Во-первых, вы можете обновить объект Player и попросить модель "обновить" данного игрока, например...

Player player = model.getPlayerAt(selectedRow);
player.setMoney(player.getMoney() + 10);
model.update(player);

или вы можете обновить модель Player с помощью метода setValueAt...

Player player = model.getPlayerAt(selectedRow);
model.setValueAt(player.getMoney() - 10, selectedRow, 1);

В качестве работающего примера...

Обновляемая таблица

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private PlayerTableModel model;

        public TestPane() {
            List<Player> players = new ArrayList<>(5);
            players.add(new Player("Han Solo", 100d));
            players.add(new Player("Dark Vadar", 100d));
            players.add(new Player("R2-D2", 100d));
            players.add(new Player("Darth Maul", 100d));
            players.add(new Player("Jawa", 100d));

            setLayout(new BorderLayout());
            model = new PlayerTableModel(players);
            JTable table = new JTable(model);
            add(new JScrollPane(table));

            JPanel actions = new JPanel();
            JButton add = new JButton("+");
            JButton subtract = new JButton("-");

            actions.add(add);
            actions.add(subtract);

            add.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    int selectedRow = table.getSelectedRow();
                    if (selectedRow >= 0) {
                        selectedRow = table.convertRowIndexToModel(selectedRow);
                        Player player = model.getPlayerAt(selectedRow);
                        player.setMoney(player.getMoney() + 10);
                        model.update(player);
                    }
                }
            });
            subtract.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    int selectedRow = table.getSelectedRow();
                    if (selectedRow >= 0) {
                        selectedRow = table.convertRowIndexToModel(selectedRow);
                        Player player = model.getPlayerAt(selectedRow);
                        model.setValueAt(player.getMoney() - 10, selectedRow, 1);
//                      player.setMoney(player.getMoney() - 10);
//                      model.update(player);
                    }
                }
            });

            add(actions, BorderLayout.SOUTH);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.dispose();
        }

    }

    public static class PlayerTableModel extends AbstractTableModel {

        protected static final String COLUMNN_NAMES[] = {"Name", "Money"};

        private List<Player> players;

        public PlayerTableModel(List<Player> players) {
            this.players = new ArrayList(players);
        }

        public Player getPlayerAt(int row) {
            return players.get(row);
        }

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

        @Override
        public int getColumnCount() {
            return COLUMNN_NAMES.length;
        }

        @Override
        public String getColumnName(int column) {
            return COLUMNN_NAMES[column];
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            Player player = players.get(rowIndex);
            Object value = null;
            switch (columnIndex) {
                case 0:
                    value = player.getName();
                    break;
                case 1:
                    value = player.getMoney();
                    break;
            }
            return value;
        }

        @Override
        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            if (columnIndex == 1) {
                Player player = players.get(rowIndex);
                player.setMoney((double)aValue);
                super.setValueAt(aValue, rowIndex, columnIndex);
                fireTableCellUpdated(rowIndex, columnIndex);
            }
        }

        public void update(Player player) {
            int row = players.indexOf(player);
            fireTableRowsUpdated(row, row);
        }

    }

    public class Player {

        private String name;
        private double money;

        public Player(String name, double money) {
            this.name = name;
            this.money = money;
        }

        public double getMoney() {
            return money;
        }

        public String getName() {
            return name;
        }

        public void setMoney(double money) {
            this.money = money;
        }

    }

}

Дело в том, что не должно быть такого разрыва между вашими игроками и вашей моделью, даже если вам нужно обернуть игрока в другой объект, чтобы вы могли расширить свойства, которые хотите отобразить, по крайней мере, таким образом, когда вы спросите для значения это то же самое значение, которое на самом деле имеет объект, и когда вы его устанавливаете, оно было установлено для того же объекта.

person MadProgrammer    schedule 16.10.2015
comment
Хотя я пытался, я думаю, что недостаточно ясно изложил свою проблему, то, что вы говорите мне, было не тем, что я искал. Однако с вашим предложением связать игроков со столом я перечитал весь свой код и на этот раз нашел ошибку. Буквально, я не знаю как, но было два экземпляра для каждого игрока, и пока деньги менялись на одном из них, другой не менялся, поэтому значения на столе тоже. Это своего рода другая проблема, кроме таблицы. Тем не мение. Большое спасибо. Проголосовал за ваши усилия, но не принял ответ, извините. - person Kutay Demireren; 16.10.2015
comment
@KutayDemireren Если бы вы использовали приведенное выше предложение, у вас, вероятно, не было бы проблемы. Итак, ошибка была в коде, который вы не предоставили, приятно видеть, что тогда никто не смог ответить на ваш вопрос. Рад, что вы нашли ответ. Вы можете удалить вопрос, так как на ваш пример кода будет невозможно ответить;) - person MadProgrammer; 16.10.2015