滚动窗格中的 JTable 仅在调整大小后显示



我的应用程序的 JFrame 逻辑如下所示:

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

包含 JTable 的JPanel是"GameHistoryPanel",它具有以下构造函数逻辑:

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

GamePanel具有以下更新例程,每当进行移动时都会调用setValueAt

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

启动游戏后,GamePanel显示为灰色。 当我垂直调整它的大小时,它突然出现所有正确的值。 我不明白为什么。 我确实注意到调整大小会导致getValueAt被调用很多次。 有人可以帮助我理解这一点吗?

编辑2:如果我添加此行:

        this.model.fireTableDataChanged();

增量,它似乎工作正常。 我完全糊涂了...

编辑:这是我的TableModel类:

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

如果我将这一行this.model.fireTableDataChanged()添加到increment(),它似乎工作正常。

您在 DataMdel 中实现setValueAt()是有缺陷的,因为它可能会向模型添加Row实例,同时仅为单个rowcol调用fireTableCellUpdated()。您需要触发适合实际修改的事件。

尝试调用

.invalidate();
.repaint();

on JPanel, JScrollPane, JTable

我的猜测是添加为increment()的最后一行

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

应该足够了。如果没有,请检查每个组件。

最新更新