Java 在fireTableDataChanged()之后突出显示JTable中的更改

Java 在fireTableDataChanged()之后突出显示JTable中的更改,java,swing,jtable,tablemodel,Java,Swing,Jtable,Tablemodel,我使用的是一个JTable,其TableModel通过fireTableDataChanged()定期更新。这些变化通常很小,例如添加或修改了一行,但是我无法预测它会发生在哪里 有没有办法知道在fireTableDataChanged()上添加或修改了哪些行?我想突出显示这些行,以便用户也知道。首先,您必须为Swing设置适当的上下文:TableModel必须对自身有足够的了解/控制,以完全遵守其通知契约。也就是说,每当发生这样的更改时,它必须激发row-/cellUpdated或rowsIns

我使用的是一个JTable,其TableModel通过
fireTableDataChanged()
定期更新。这些变化通常很小,例如添加或修改了一行,但是我无法预测它会发生在哪里


有没有办法知道在
fireTableDataChanged()
上添加或修改了哪些行?我想突出显示这些行,以便用户也知道。

首先,您必须为Swing设置适当的上下文:TableModel必须对自身有足够的了解/控制,以完全遵守其通知契约。也就是说,每当发生这样的更改时,它必须激发row-/cellUpdated或rowsInserted

然后,突出显示JTable中的更改(特定时间)的基本方法是

  • 实现一个自定义渲染器,用于装饰某些存储中的单元
  • 使用自定义渲染器配置表
  • 倾听模型的变化
  • 将changeEvents(或具有相关属性的自定义对象)添加到渲染器知道的存储中
  • 使用计时器在一段时间后删除更改标记
通过提供Highlighter和HighlightPredicates简化了渲染部分(偏向于me:-):前者在后者决定应该打开时进行自定义视觉装饰。上述方法将根据需要进行调整

  • 为桌子配置荧光灯,以进行视觉装饰
  • 倾听模型中的变化
  • 将更改后的单元格添加到自定义高亮谓词,并使用它配置高亮
  • 使用计时器在一段时间后删除更改标记
下面是一些代码,将计时器/谓词的管理分解到一个名为ChangeDecorator的类中:它保留一个高亮灯用于装饰更新的单元格,另一个用于装饰插入的行(注意:这是一个示例,显然必须扩展逻辑以覆盖更新的行:)它由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;
    }

}
JXTable表=新的JXTable(模型);
最终ChangeDecorator控制器=新的ChangeDecorator();
table.addHighlighter(controller.getChangeHighlighter());
TableModelListener l=新的TableModelListener(){
@凌驾
公共作废表已更改(TableModelEvent e){
if(TableUtilities.isUpdate(e)){
Change Change=新更改(e.getFirstRow(),e.getColumn());
控制器。添加更改(更改);
}else if(TableUtilities.isInsert(e)){
Change Change=新的更改(例如getFirstRow());
控制器。添加更改(更改);
}
}
};
model.addTableModelListener(l);
/**
*管理插入行/更新单元格的高亮显示。
*/
公共静态类变更装饰器{
私人名单变更;
私人荧光灯更新;
私人荧光灯插页;
私人荧光灯化合物;
公共变更装饰器(){
changes=新的ArrayList();
}
公共荧光灯getChangeHighlighter(){
if(复合==null){
更新=新的彩色荧光灯(新的ChangePredicate(更改,真),
颜色:黄色,空);
插入=新的彩色荧光灯(新的ChangePredicate(更改,错误),
颜色:绿色,空);
化合物=新化合物荧光灯(更新、插入);
}
返回化合物;
}
公共无效添加更改(更改更改){
startTimer(change,change.isCell?更新:插入);
}
私有void startTimer(最终变更、最终抽象){
更改。添加(更改);
hl.setHighlightPredicate(newchangePredicate(changes,change.isCell));
ActionListener l=新的ActionListener(){
布尔完成;
@凌驾
已执行的公共无效操作(操作事件e){
如果(!完成){
完成=正确;
返回;
}
((计时器)e.getSource()).stop();
更改。删除(更改);
hl.setHighlightPredicate(newchangePredicate(changes,change.isCell));
}
};
定时器=新定时器(2000,l);
定时器。设置初始延迟(100);
timer.start();
}
}
/**
*谓词启用高亮显示单元格,如果它
*包含对该单元格的更改。
*/
公共静态类ChangePredicate实现HighlightPredicate{
私人名单变更;
私有布尔匹配单元;
公共ChangePredicate(列表更改,布尔匹配单元格){
this.changes=新的ArrayList(变更);
this.matchCell=matchCell;
}
@凌驾
公共布尔isHighlighted(组件渲染器,
组件适配器(适配器){
returnchanges.contains(createChange(adapter));
}
私有更改createChange(组件适配器){
int modelRow=adapter.convertRowIndexToModel(adapter.row);
if(匹配单元){
int模型列=
adapter.convertColumnIndexToModel(adapter.column);;
返回新更改(modelRow、modelColumn);
}
返回新更改(modelRow);
}
}
/**
*封装单元格更改的原始类。
* 
*/
公共静态类变更{
int行;
int列;
布尔isCell;
公共变更(国际行){
这(第-1行,错误);
}
公共更改(整数行,整数列){
这(行、列、真);
}
私有更改(整数行、整数列、布尔更新){
this.row=行;
this.column=col;
this.isCell=更新;
}
@凌驾
公共布尔等于(对象obj){
如果(!(obj instanceof Change))返回false;
变更其他=(变更)obj;
返回row==other.row&&column==other.column&&isCell==other.isCell;
}
}

首先,您必须为Swing:TableMo设置适当的上下文