My Java 8 app uses a JTable
inside a JScrollPane
. Currently the table has more than 10 columns and the data is added using DefaultTableModel
's addRow(someObjectArray)
. All cells in a column currently have the same type of data but columns 4+ can contain cells with "null" (0-3 always contain data != null!).
If the data in the first three columns isn't the same as the data in the previous row, the first three cells in the current row are written in a black, bold font, otherwise they use the normal, plain and dark grey font - it's simply a way to mark the beginning of new data:
Filling the table and scrolling vertically sets the bold font and plain font properly but scrolling right and then back to the first three columns, the bold font is messed up: It's sometimes set for every cell, sometimes for the wrong cells and sometimes it changes mid-text:
Scrolling down and up again resets the cells to what they should look like.
This is how the table is set up:
JTable myTable = new JTable() {
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
if (column<3) {
if(row==0) { //Always mark column 0-2 in row 0
c.setFont(c.getFont().deriveFont(Font.BOLD));
c.setForeground(Color.BLACK);
} else {
if(column==0) { //Check if column 0-2 should be marked and mark column 0 (or not)
Object prevColumnA = getValueAt(row-1, column); //String
Object currColumnA = getValueAt(row, column); //String
Object prevColumnB = getValueAt(row-1, column+1); //int
Object currColumnB = getValueAt(row, column+1); //int
Object prevColumnC = getValueAt(row-1, column+2); //String
Object currColumnC = getValueAt(row, column+2); //String
if(!prevColumnA.equals(currColumnA) || !prevColumnB.equals(currColumnB) || !prevColumnC.equals(currColumnC)) {
markRow = true;
c.setFont(c.getFont().deriveFont(Font.BOLD));
c.setForeground(Color.BLACK);
} else {
markRow = false;
c.setFont(c.getFont().deriveFont(Font.PLAIN));
c.setForeground(Color.DARK_GRAY);
}
} else { //Mark column 1-2 (or not)
if(markRow) {
c.setFont(c.getFont().deriveFont(Font.BOLD));
c.setForeground(Color.BLACK);
} else {
c.setFont(c.getFont().deriveFont(Font.PLAIN));
c.setForeground(Color.DARK_GRAY);
}
}
}
} else {
c.setFont(c.getFont().deriveFont(Font.PLAIN));
c.setForeground(Color.DARK_GRAY);
}
//System.out.println("row="+row+", column="+column+", markRow="+markRow);
return c;
}
};
How do I fix this?
Edit: MRE copied from here:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class SomeMRE extends JPanel {
boolean markRow = false;
public SomeMRE() {
JTable myTable = new JTable() {
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
if (column<3) {
if(row==0) { //Always mark column 0-2 in row 0
c.setFont(c.getFont().deriveFont(Font.BOLD));
c.setForeground(Color.BLACK);
} else {
if(column==0) { //Check if column 0-2 should be marked and mark column 0 (or not)
Object prevColumnA = getValueAt(row-1, column); //String
Object currColumnA = getValueAt(row, column); //String
Object prevColumnB = getValueAt(row-1, column+1); //int
Object currColumnB = getValueAt(row, column+1); //int
Object prevColumnC = getValueAt(row-1, column+2); //String
Object currColumnC = getValueAt(row, column+2); //String
if(!prevColumnA.equals(currColumnA) || !prevColumnB.equals(currColumnB) || !prevColumnC.equals(currColumnC)) {
markRow = true;
c.setFont(c.getFont().deriveFont(Font.BOLD));
c.setForeground(Color.BLACK);
} else {
markRow = false;
c.setFont(c.getFont().deriveFont(Font.PLAIN));
c.setForeground(Color.DARK_GRAY);
}
} else { //Mark column 1-2 (or not)
if(markRow) {
c.setFont(c.getFont().deriveFont(Font.BOLD));
c.setForeground(Color.BLACK);
} else {
c.setFont(c.getFont().deriveFont(Font.PLAIN));
c.setForeground(Color.DARK_GRAY);
}
}
}
} else {
c.setFont(c.getFont().deriveFont(Font.PLAIN));
c.setForeground(Color.DARK_GRAY);
}
//System.out.println("row="+row+", column="+column+", markRow="+markRow);
return c;
}
};
myTable.setModel(new DefaultTableModel(
new Object[][] {
{"ColumnA text 1", 123, "ColumnC text 1", 1, null, "bla", "bla", "bla", null},
{"ColumnA text 2", 234, "ColumnC text 2", 2, null, "bla", "bla", null, null},
{"ColumnA text 2", 234, "ColumnC text 2", 3, null, "bla", "bla", "bla", null},
{"ColumnA text 2", 234, "ColumnC text 2", 4, null, "bla", "bla", null, null},
{"ColumnA text 2", 234, "ColumnC text 2", 5, null, "bla", null, null, null},
{"ColumnA text 1", 123, "ColumnC text 1", 6, null, "bla", "bla", "bla", null},
{"ColumnA text 2", 234, "ColumnC text 2", 7, null, "bla", null, null, null},
{"ColumnA text 2", 234, "ColumnC text 2", 8, null, "bla", "bla", null, null},
{"ColumnA text 2", 234, "ColumnC text 2", 9, null, "bla", "bla", null, null}
},
new String[] {
"ColumnA", "ColumnB", "ColumnC", "ColumnD", "ColumnE", "ColumnF", "ColumnG", "ColumnH", "ColumnI"
}
));
setLayout( new BorderLayout() );
add(new JScrollPane(myTable));
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("SomeMRE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SomeMRE());
frame.pack();
frame.setVisible( true );
}
public static void main(String[] args) throws Exception {
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
}
}