Reputation: 131
I tried to find here for a long time answer for my question but without the exact result i expected.
I have JTable which every time i am changing values in entire column (only in one column every time). I want to listen to a table changes and when data changes in the column, the color in the column will be changed too and all other columns will be in the default color.
This is the code for the table listener:
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 ;
}
}
and this is the code for the table creation:
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);
}
Upvotes: 1
Views: 1602
Reputation: 205785
Store the desired state in the TableModel
; let the TableCellRenderer
use the state to condition the view accordingly. In the example below, as soon as setValueAt()
updates any cell, edited
is marked true
. The render, which is applied to column zero, changes the display accordingly. Note how clearEdited()
invokes fireTableDataChanged()
to force the table to render all cells when called in the Clear handler.
Addendum: The update below shows one approach to handling multiple columns independently. The CustomModel
now contains a Map<Integer, Boolean>
to store the edited state for each column to which the CustomRenderer
is applied. As an aside, the CustomRenderer
now invokes convertColumnIndexToModel()
and sets the selection color correctly.
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 http://stackoverflow.com/a/37439731/230513
*/
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);
}
}
Upvotes: 1