我的应用程序的 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
实例,同时仅为单个row
和col
调用fireTableCellUpdated()
。您需要触发适合实际修改的事件。
尝试调用
.invalidate();
.repaint();
on JPanel, JScrollPane, JTable
我的猜测是添加为increment()
的最后一行
JTable.invalidate();
JTable.repaint();
应该足够了。如果没有,请检查每个组件。