简体   繁体   中英

The data in JTable doesn't change

I tried so far too much and was reading lots of things. Still couldn't find any working solution on my case. So, here is the deal. During the game, players money are changing. What I am trying to achieve is to display money instantly from the JTable , so the player can always follow his money by simply looking at the table. But, as you can assume, I failed at changing the money when it is changed. It just stays at the amount of how it started.

What I got so far is a well-built JTable which shows the initial money of player at beginning and a custom model for my JTable .

Since I believe the solution relies on the model and setValuesAt(Object value, int row, int column) , I was trying to figure a way out there. What I got there is a method called refresh. To be more specific, let me show you some fraction of my code.

So here is my rowData array in the constructor, which I'm using for displaying the initial money at the beginning of the game:

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

By saying that, I also need to show you these two following functions, setValueAt and refresh(refresh is a method I just wrote for simplicity for updating changes):

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

Here, in the refresh, I am only trying to change the second (2nd) row because the first two are static and never changes. Also, the number 4 in the for loop is the number of players, so that 4 holds the number of rows.

You can find at below the whole my table model code:

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

}

And that is how I use in the Gui class:

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

Hope those are enough to show, if needed I can show more but since this is a school project I am avoiding to show much.

It's a little hard to figure out what the problem might be based on the out-of-context code you have provided.

When ever I deal with a JTable , I use it to model the physical data, in your case, that's the Player object. This way, if the Player is modified outside of the table, you simply need to trigger a update to the model to have the table refresh the values. Equally, you can also centralise some of the functionality to the table and use it to modify the Player object directly.

This way, the model and the data are always in sync (even if the display isn't)

In this example, there are two ways to update the model/table.

First, you could update the Player object and ask the model to "refresh" the given player, for example...

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

or you could have the model update the Player via the setValueAt method...

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

As a runnable example...

可更新表

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

    }

}

The point is, there shouldn't be such a disconnection between your players and your model, even if you need to wrap the player into another object so you can expand on the properties you want to display, at least this way, when you ask for a value, it's the same value that the object actually has and when you set it, it's been set on the same object.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM