Amir Afghani
Amir Afghani

Reputation: 38541

JTable inside of ScrollPane only shows up after resize

My application's JFrame logic looks like:

public Table() {
    super("Chess");
    thisFrame = this;
    tableMenuBar = new JMenuBar();
    populateMenuBar();
    setJMenuBar(tableMenuBar);
    getContentPane().setLayout(new BorderLayout());
    chessBoard = new Board(new StandardBoardConfigurator());
    gamePanel = new GameHistoryPanel();
    chatPanel = new ChatPanel();
    takenPiecesPanel = new TakenPiecesPanel();
    boardPanel = new BoardPanel(chessBoard);
    gameProgress = 1;
    highlightLegalMoves = true;
    moveLog = new ArrayList<Move>();
    gameOver = false;
    getContentPane().add(takenPiecesPanel, BorderLayout.WEST);
    getContentPane().add(boardPanel, BorderLayout.CENTER);
    getContentPane().add(gamePanel, BorderLayout.EAST);
    getContentPane().add(chatPanel, BorderLayout.SOUTH);
    // Make sure we have nice window decorations.
    setDefaultLookAndFeelDecorated(true);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(OUTER_FRAME_DIMENSION);
    pack();
    setVisible(true);
}

and the JPanel containing the JTable is 'GameHistoryPanel', which has this as it's constructor logic:

    public GameHistoryPanel() {
        this.setLayout(new BorderLayout());
        this.model = new DataModel();
        this.table = new JTable(model);
        this.table.setRowHeight(15);
        final JScrollPane scrollPane = new JScrollPane(this.table);
        scrollPane.setColumnHeaderView(table.getTableHeader());
        scrollPane.setPreferredSize(HISTORY_PANEL_DIMENSION);
        this.add(scrollPane, BorderLayout.CENTER);
        this.currentRow = 0;
        this.currentColumn = 0;
        this.setVisible(true);
    }

The GamePanel has the following update routine which calls setValueAt whenever a move is made:

    public void increment(final Board board,
                          final Move move) {
        this.model.setValueAt(move, currentRow, currentColumn);
        if(board.currentPlayer().getAlliance() == Alliance.WHITE) {
            currentColumn++;
        } else if (board.currentPlayer().getAlliance() == Alliance.BLACK) {
            currentRow++;
            currentColumn = 0;
        }
    }

Upon launching the game, the GamePanel is grayed out. When I resize it vertically, it suddenly appears with all of the correct values. I don't understand why. I did notice that resizing causes getValueAt to be invoked a bunch of times. Can someone help me understand this?

EDIT 2: If I add this line:

        this.model.fireTableDataChanged();

to increment, it seems to work fine. I'm wholly confused...

EDIT: Here is my TableModel class:

    private static class DataModel extends AbstractTableModel {

        private static final String[] names = {"White", "Black"};
        private final List<Row> values;

        public DataModel() {
            values = new ArrayList<Row>();
        }

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

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

        @Override
        public Object getValueAt(int row, int col) {
            final Row currentRow = values.get(row);
            if(col == 0) {
                return currentRow.getWhiteMove();
            } else if (col == 1) {
                return currentRow.getBlackMove();
            }
            return null;
        }

        @Override
        public void setValueAt(Object aValue, int row, int col) {
            final Row currentRow;
            if(values.size() <= row) {
                currentRow = new Row();
                values.add(currentRow);
            } else {
                currentRow = values.get(row);
            }
            if(col == 0) {
                currentRow.setWhiteMove((Move) aValue);
            } else  if(col == 1) {
                currentRow.setBlackMove((Move)aValue);
            }
            this.fireTableCellUpdated(row, col);
        }

        @Override
        public Class<?> getColumnClass(int col) {
            return Move.class;
        }

        @Override
        public String getColumnName(int col) {
            return names[col];
        }
    }
}

Upvotes: 1

Views: 1658

Answers (2)

trashgod
trashgod

Reputation: 205865

If I add this line, this.model.fireTableDataChanged(), to increment(), it seems to work fine.

Your implementation of setValueAt() in DataMdel is flawed in that it may add instances of Row to the model, while only invoking fireTableCellUpdated() for a single row and col. You need to fire the event appropriate to the actual modification.

Upvotes: 2

Nikolay Kuznetsov
Nikolay Kuznetsov

Reputation: 9579

Try to call

.invalidate();
.repaint();

on either JPanel, JScrollPane, JTable

My guess is that adding as last lines of increment()

JTable.invalidate();
JTable.repaint();

should be sufficient. If not, please, check for each component.

Upvotes: 1

Related Questions