JTable调用fireTableChanged后界面不刷新,该传入模型行还是视图行?
JTable fireTableChanged 索引疑问与问题排查
先给你明确结论:TableModelEvent里必须传的是模型行/列ID,绝对不能用视图层面的索引。Swing的MVC设计里,TableModel只管数据,视图(JTable)管展示、排序过滤这些,所以模型发出的事件肯定是基于自己的索引体系的。
咱们来拆解你贴的JTable源码:
public class JTable extends JComponent implements TableModelListener, Scrollable, ... public void tableChanged(TableModelEvent e) { ... int modelColumn = e.getColumn(); int start = e.getFirstRow(); int end = e.getLastRow(); Rectangle dirtyRegion; if (modelColumn == TableModelEvent.ALL_COLUMNS) { // 1 or more rows changed dirtyRegion = new Rectangle(0, start * getRowHeight(), getColumnModel().getTotalColumnWidth(), 0); } else { // A cell or column of cells has changed. // Unlike the rest of the methods in the JTable, the TableModelEvent // uses the coordinate system of the model instead of the view. // This is the only place in the JTable where this "reverse mapping" // is used. int column = convertColumnIndexToView(modelColumn); dirtyRegion = getCellRect(start, column, false); }
这里注释里的"reverse mapping"很好理解:平时我们用JTable的大多数方法(比如getSelectedRow())拿到的都是视图索引,需要转成模型索引得用convertRowIndexToModel();但这里反过来——TableModelEvent传的是模型索引,所以要转成视图索引(convertColumnIndexToView())才能找到界面上的位置。
那为啥代码里没转行索引?因为在没有启用RowSorter(也就是没排序、没过滤)的场景下,模型行和视图行是一一对应的,模型行号直接等于视图行号,所以不用转。但如果开了排序/过滤,这部分逻辑就交给RowSorter处理了,就是你后面贴的那段代码:
private void repaintSortedRows(ModelChange change) { ... int modelIndex = change.startModelIndex; while (modelIndex <= change.endModelIndex) { int viewIndex = convertRowIndexToView(modelIndex++); if (viewIndex != -1) { Rectangle dirty = getCellRect(viewIndex, columnViewIndex, false); int x = dirty.x; int w = dirty.width; if (eventColumn == TableModelEvent.ALL_COLUMNS) { x = 0; w = getWidth(); } repaint(x, dirty.y, w, dirty.height); } } }
你看,RowSorter会把模型索引转成视图索引再去重绘,这是Swing的分工设计,不是bug哦。
至于你一开始遇到的界面不刷新,最后发现是自定义模型的问题——太懂这种感觉了!复杂的自定义TableModel很容易在索引计算、事件触发时机上踩坑,比如可能你传的rowNumber不是正确的模型行ID,或者模型内部数据更新和事件触发不同步。
最后再划个重点:
- 调用
fireTableChanged时,必须传模型层面的行/列索引 - 无RowSorter时,JTable直接用模型行索引计算脏区域;有RowSorter时,RowSorter负责索引转换和重绘
- 遇到不刷新先查自定义模型的索引和事件逻辑,别先怀疑Swing的设计
内容的提问来源于stack exchange,提问作者AlexP
相关产品推荐
相关产品推荐

