ADDITIONAL SYSTEM INFORMATION :
Mac & Linux
A DESCRIPTION OF THE PROBLEM :
This code used to work in Java 7 & 8 but seems to be broken in Java 10 (and possibly 9). I've tested both on Linux and Mac and it is broken in both.
REGRESSION : Last worked in version 8u172
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and run the the attached class ChainedModelTester.java
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A window should pop up and the rows should be updated one by one and repaint (Java 8).
ACTUAL -
On Java 10, rows go blank and don't repaint unless clicked on.
---------- BEGIN SOURCE ----------
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import java.awt.*;
import java.util.Random;
public class ChainedModelTester {
public static void main(String[] args) throws InterruptedException {
final String[] columnNames = {"Name1", "Name2", "Name3", "Name4", "Name5"};
final TableModel tm1 = new DefaultTableModel(new Object[][] {{"foo", "bar", "baz", "bat", "boz"}}, columnNames);
TableModel kvM = new KeyValueModel(tm1, 4);
JTable table = new JTable(kvM);
JFrame parent = new JFrame("Key Values");
parent.setLayout(new FlowLayout());
parent.add(table);
JWindow window = new JWindow(parent);
table.setSize(500,300);
parent.pack();
parent.setVisible(true);
Thread.sleep(1000);
final Random r = new Random();
for (int i = 0; i< 1000; i++) {
final int typeIdx = i % (columnNames.length - 1);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final String aValue = String.valueOf(r.nextInt(1000));
tm1.setValueAt(aValue, 0, typeIdx);
}
});
Thread.sleep(1000);
}
}
//Shows a subset of the columns in another model as key/value pairs
static class KeyValueModel extends AbstractTableModel {
TableModel sourceModel;
final int firstN;
KeyValueModel(final TableModel sourceModel, final int firstN) {
if (firstN < 1 || firstN > sourceModel.getColumnCount()) {
throw new IllegalArgumentException("Illegal firstN "+firstN);
}
this.firstN = firstN;
this.sourceModel = sourceModel;
sourceModel.addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
int col = e.getColumn();
if (col < firstN) {
// fireTableDataChanged();
fireTableRowsUpdated(col,col);
} else {
System.out.println("Out of range "+col);
}
}
});
}
@Override
public int getRowCount() {
return firstN;
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
return sourceModel.getColumnName(rowIndex);
} else {
return sourceModel.getValueAt(0, rowIndex);
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
call fireTableDataChanged(), which although inefficient, does repaint everything.
FREQUENCY : always