当值更改时,JTable 更改整个列的颜色 - Swing

JTable change color for entire column when values changed - Swing

我试图在这里找到我的问题的很长时间的答案,但没有得到我预期的确切结果。

我有 JTable,每次我更改整列中的值时(每次只更改一列)。 我想听 table 变化,当列中的数据发生变化时,列中的颜色也会发生变化,所有其他列都将采用默认颜色。

这是 table 侦听器的代码:

Class CustomCellRenderer extends DefaultTableCellRenderer {

    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

        Component rendererComp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        table.getModel().addTableModelListener(new TableModelListener() {

            @Override
            public void tableChanged(TableModelEvent e) {
                if(***here i want to know which column changed or something like that***){
                    rendererComp.setBackground(Color.CYAN);
                }

            }
        });

        return rendererComp ;
    }

}

这是 table 创建的代码:

private void createTable() {

        tablePanel.setLayout(new FlowLayout(FlowLayout.LEFT));

        DefaultTableModel tableModel = new DefaultTableModel(){

            @Override
            public boolean isCellEditable(int row, int column) {
               //all cells false
               return false;
            }
        };
        contentTable = new JTable(tableModel);

        contentTable.setGridColor(Color.LIGHT_GRAY);

        for(int i=0; i<columnSize; i++) {
            tableModel.addColumn("0");
        }

        for(int i=0; i<rawSize; i++) {
            tableModel.addRow(new Object[] { "" });
        }

        for(int i=0; i<rawSize; i++) {
            for(int j=0; j<tableModel.getRowCount(); j++) {
                tableModel.setValueAt("0", j, i);
            }
        }

        for(int i=0; i<ramSize; i++) {
            contentTable.getColumnModel().getColumn(i).setCellRenderer(new CustomCellRenderer());
        }

        JScrollPane scrollPane = new JScrollPane(contentTable);
        scrollPane.setPreferredSize(new Dimension(400, 150));

        tablePanel.add(scrollPane);
}

TableModel中存储所需的状态;让 TableCellRenderer 使用状态来相应地调节视图。在下面的示例中,只要 setValueAt() 更新任何单元格,edited 就会被标记为 true。应用于零列的渲染会相应地更改显示。请注意 clearEdited() 如何调用 fireTableDataChanged() 以强制 table 在 Clear 处理程序中调用时呈现所有单元格。

附录:下面的更新展示了一种独立处理多列的方法。 CustomModel 现在包含一个 Map<Integer, Boolean> 来存储应用了 CustomRenderer 的每个列的编辑状态。另外,CustomRenderer 现在调用 convertColumnIndexToModel() 并正确设置选择颜色。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

/**
 * @see 
 */
public class Test {

    private void display() {
        JFrame f = new JFrame("Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        CustomModel model = new CustomModel();
        model.setColumnIdentifiers(new String[]{"A", "B"});
        for (int i = 0; i < 16; i++) {
            model.addRow(new String[]{"A:" + i, "B:" + i});
        }
        JTable table = new JTable(model) {
            @Override
            public Dimension getPreferredScrollableViewportSize() {
                return new Dimension(100, getRowHeight() * getRowCount() / 2);
            }
        };
        table.getColumnModel().getColumn(0).setCellRenderer(new CustomRenderer(model));
        table.getColumnModel().getColumn(1).setCellRenderer(new CustomRenderer(model));
        f.add(new JScrollPane(table));
        JPanel p = new JPanel();
        p.add(new JButton(new UpdateAction("Update A", model, 0)));
        p.add(new JButton(new UpdateAction("Update B", model, 1)));
        p.add(new JButton(new AbstractAction("Clear") {
            @Override
            public void actionPerformed(ActionEvent e) {
                model.clearEdited(0);
                model.clearEdited(1);
            }
        }));
        f.add(p, BorderLayout.SOUTH);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    private static class CustomModel extends DefaultTableModel {

        private final Map<Integer, Boolean> edited = new HashMap<>();

        public boolean isEdited(int column) {
            return edited.get(column) != null && edited.get(column);
        }

        public void clearEdited(int column) {
            edited.put(column, false);
            fireTableDataChanged();
        }

        @Override
        public boolean isCellEditable(int row, int column) {
            return false;
        }

        @Override
        public void setValueAt(Object aValue, int row, int column) {
            super.setValueAt(aValue, row, column);
            edited.put(column, true);
        }
    }

    private static class CustomRenderer extends DefaultTableCellRenderer {

        private final CustomModel model;

        public CustomRenderer(CustomModel model) {
            this.model = model;
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int col) {
            Component c = super.getTableCellRendererComponent(
                table, value, isSelected, hasFocus, row, col);
            if (model.isEdited(table.convertColumnIndexToModel(col))) {
                c.setBackground(Color.cyan);
            } else if (isSelected) {
                c.setBackground(table.getSelectionBackground());
            } else {
                c.setBackground(table.getBackground());
            }
            return c;
        }
    }

    private static class UpdateAction extends AbstractAction {

        private final CustomModel model;
        private final int column;

        public UpdateAction(String name, CustomModel model, int column) {
            super(name);
            this.model = model;
            this.column = column;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            for (int i = 0; i < model.getRowCount(); i++) {
                model.setValueAt(model.getValueAt(i, column), i, column);
            }
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Test()::display);
    }
}