我的Java 8应用在JTable
中使用了JScrollPane
。当前,该表有10多个列,并且使用DefaultTableModel
的addRow(someObjectArray)
添加数据。当前列中的所有单元格都具有相同类型的数据,但是列4+可以包含具有“ null”的单元格(0-3始终包含数据!= null!)。
如果前三列中的数据与上一行中的数据不同,则当前行中的前三个单元格以黑色,粗体字体书写,否则将使用普通,纯灰色和深灰色字体-这只是标记新数据开始的一种方式:
填充表格并垂直滚动会正确设置粗体字体和普通字体,但是向右滚动然后返回到前三列,粗体字体会被弄乱:有时为每个单元格设置,有时为错误的单元格设置,有时更改中间文本:
再次上下滚动将单元格重置为它们的外观。
这是表格的设置方式:
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;
}
};
我该如何解决?
编辑:从here复制的MRE:
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() );
}
}
[最好是独立地为每个单元格单独确定设置,而不使用在某个特定单元格坐标(例如,行中的第一个单元格)确定的变量(代码片段中的markRow
。
原因是没有确定的方式调用prepareRenderer
。不能保证首先对第一行中的第一个单元格调用此方法,然后对第一行中的第二个单元格调用此方法,依此类推。换句话说,不要指望prepareRenderer
以连续方式或任何特定顺序被调用。
还要注意,应为每个单元格正确初始化渲染器组件。在the first version of your question的代码片段中,else
的开头没有if(column<3)
部分,这意味着该组件可能已被任意初始化。如果存在准备渲染器的决策树,请确保所有路径均根据需要准备渲染器。
首先,不是MRE。您陈述的问题是:
但是向右滚动然后返回到前三列,粗体字体被弄乱了:
嗯,您发布的代码不会进行水平滚动,因此您不可能测试过您发布的代码以确保它能够证明您所陈述的问题。
您是否在测试粗体条件之前查看了有关删除“ markRow”变量并设置默认呈现的原始评论?
当我尝试上述建议时,我能够大大简化代码:
JTable myTable = new JTable()
{
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
{
Component c = super.prepareRenderer(renderer, row, column);
c.setForeground(Color.DARK_GRAY);
if (column < 3)
{
if(row == 0) { //Always mark columns 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)
TableModel model = getModel();
Object prevColumn0 = model.getValueAt(row-1, 0); //String
Object currColumn0 = model.getValueAt(row, 0); //String
Object prevColumn1 = model.getValueAt(row-1, 1); //int
Object currColumn1 = model.getValueAt(row, 1); //int
Object prevColumn2 = model.getValueAt(row-1, 2); //String
Object currColumn2 = model.getValueAt(row, 2); //String
if (!prevColumn0.equals(currColumn0)
|| !prevColumn1.equals(currColumn1)
|| !prevColumn2.equals(currColumn2))
{
c.setFont(c.getFont().deriveFont(Font.BOLD));
c.setForeground(Color.BLACK);
}
}
}
return c;
}
};
据我了解,它会迭代当前显示的单元格,然后为每个单元格设置渲染器。
不要对渲染顺序进行假设。每个单元都独立于其他单元进行渲染。这就是为什么您不希望依赖从呈现的上一个单元格设置的变量的原因。