我正在使用一个 JTable,它的 TableModel 通过fireTableDataChanged()
. 这些更改通常很小,例如添加或修改了一行,但是我无法预测它会发生在哪里。
有没有办法知道在 a 上添加或修改了哪些行fireTableDataChanged()
?我想突出显示这些行,以便用户也知道。
我正在使用一个 JTable,它的 TableModel 通过fireTableDataChanged()
. 这些更改通常很小,例如添加或修改了一行,但是我无法预测它会发生在哪里。
有没有办法知道在 a 上添加或修改了哪些行fireTableDataChanged()
?我想突出显示这些行,以便用户也知道。
首先,您必须为 Swing 设置适当的上下文:TableModel必须对自己有足够的了解/控制才能完全遵守其通知合同。也就是说,每当发生此类更改时,它都必须触发 row-/cellUpdated 或 rowsInserted。
然后在 JTable 中突出显示更改(一段时间)的基本方法是
SwingX通过提供 Highlighters 和 HighlightPredicates 来简化(偏向于我 :-) 渲染部分:当后者决定应该打开它们时,前者会进行自定义视觉装饰。上述方法将调整为
下面是一些代码,定时器/谓词的管理被分解到一个名为 ChangeDecorator 的类中:它保留一个用于装饰更新单元格的荧光笔和一个用于装饰插入行的荧光笔(注意:这是一个示例,显然必须扩展逻辑以涵盖更新rows :) 它由 modelListener 提供,并根据需要进行更改并更新谓词。
JXTable table = new JXTable(model);
final ChangeDecorator controller = new ChangeDecorator();
table.addHighlighter(controller.getChangeHighlighter());
TableModelListener l = new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
if (TableUtilities.isUpdate(e)) {
Change change = new Change(e.getFirstRow(), e.getColumn());
controller.addChange(change);
} else if (TableUtilities.isInsert(e)) {
Change change = new Change(e.getFirstRow());
controller.addChange(change);
}
}
};
model.addTableModelListener(l);
/**
* Manages the Highlighters for inserted rows/updated cells.
*/
public static class ChangeDecorator {
private List<Change> changes;
private AbstractHighlighter update;
private AbstractHighlighter insert;
private Highlighter compound;
public ChangeDecorator() {
changes = new ArrayList<>();
}
public Highlighter getChangeHighlighter() {
if (compound == null) {
update = new ColorHighlighter(new ChangePredicate(changes, true),
Color.YELLOW, null);
insert = new ColorHighlighter(new ChangePredicate(changes, false),
Color.GREEN, null);
compound = new CompoundHighlighter(update, insert);
}
return compound;
}
public void addChange(Change change) {
startTimer(change, change.isCell ? update : insert);
}
private void startTimer(final Change change, final AbstractHighlighter hl) {
changes.add(change);
hl.setHighlightPredicate(new ChangePredicate(changes, change.isCell));
ActionListener l = new ActionListener() {
boolean done;
@Override
public void actionPerformed(ActionEvent e) {
if (!done) {
done = true;
return;
}
((Timer) e.getSource()).stop();
changes.remove(change);
hl.setHighlightPredicate(new ChangePredicate(changes, change.isCell));
}
};
Timer timer = new Timer(2000, l);
timer.setInitialDelay(100);
timer.start();
}
}
/**
* A predicate enables highlighting a cell if it
* contains a change for that cell.
*/
public static class ChangePredicate implements HighlightPredicate {
private List<Change> changes;
private boolean matchCell;
public ChangePredicate(List<Change> changes, boolean matchCell) {
this.changes = new ArrayList(changes);
this.matchCell = matchCell;
}
@Override
public boolean isHighlighted(Component renderer,
ComponentAdapter adapter) {
return changes.contains(createChange(adapter));
}
private Change createChange(ComponentAdapter adapter) {
int modelRow = adapter.convertRowIndexToModel(adapter.row);
if (matchCell) {
int modelColumn =
adapter.convertColumnIndexToModel(adapter.column);;
return new Change(modelRow, modelColumn);
}
return new Change(modelRow);
}
}
/**
* A crude class encapsulating a cell change.
*
*/
public static class Change {
int row;
int column;
boolean isCell;
public Change(int row) {
this(row, -1, false);
}
public Change(int row, int col) {
this(row, col, true);
}
private Change(int row, int col, boolean update) {
this.row = row;
this.column = col;
this.isCell = update;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Change)) return false;
Change other = (Change) obj;
return row == other.row && column == other.column && isCell == other.isCell;
}
}