我的Java 8小程序连接到SQL数据库,并在带有两列的JTable
中显示“ select”语句的结果:
如果第1行/ ColumnA中的字符串与第0行/ ColumnA中的字符串不同,我想给第1行提供灰色背景色(以标记“新”数据的开始),其他行应该使用默认的白色。
用于创建表的代码:
JTable myTable = new JTable();
myTable.setSelectionModel(new ToggleListSelectionModel()); //custom selection model
myTable.setModel(new DefaultTableModel(
new Object[][] {
},
new String[] {
"ColumnA", "ColumnB"
}
));
获取数据并填写表格:
Statement stat = connection.createStatement();
ResultSet rs = stat.executeQuery(someSelectStatement);
Object[] row = null;
while(rs.next()) {
int columns = rs.getMetaData().getColumnCount();
row = new Object[columns];
for (int i=1; i<=columns; i++) {
row[i - 1] = rs.getObject(i);
}
//TODO: Set color of row according to data in "ColumnA" of previous row
((DefaultTableModel) myTable.getModel()).insertRow(rs.getRow()-1,row); //Add new row with the ResultSet's content
//Get String data of ColumnA for this specific row with e.g. "(String) row[0]"
}
rs.close();
stat.close();
根据到目前为止的发现,我必须使用自定义TableModel
而不是开始时设置的DefaultTableModel
,但是如何使用它呢?我发现的所有内容都使用固定检查,例如
如果单元格中的内容为“购买”,则将背景色设置为“绿色”
(例如here或here),但是在我的情况下,创建表时我对内容一无所知,因为表已填充/行在运行时添加。
我也找到了this的答案,但是问题的作者读取了数据,然后更改了模型,然后才填充了表格,同时我逐行填充了表格(直接在读取行的内容之后)。
我的问题:我知道如何将单元格的内容与上一行中的单元格的内容进行比较,但是如何在运行时设置行的背景色?
编辑:
这是一些用于填写表格的MRE代码。请注意:如果您对如何完成自己的工作提出建议,请记住我正在使用数据库和ResultSet
(请参见上面的代码)而不是预定义的数据(请参见代码)下面)!
JTable myTable = new JTable();
myTable.setSelectionModel(new ToggleListSelectionModel()); //custom selection model
myTable.setModel(new DefaultTableModel(
new Object[][] {
{"1000", 123},
{"1000", 234},
{"1001", 123},
{"1002", 123},
{"1002", 234},
{"1002", 345},
{"1003", 123},
{"1003", 234}
},
new String[] {
"ColumnA", "ColumnB"
}
));
结果:
所需的结果(每个新的“ A列”值的背景为灰色):
替代结果(替代标记组的所有行):
答案 0 :(得分:2)
table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
Component comp = super.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
if(!isSelected) { //Important check, see comment below!
boolean levelBreak = row == 0;
if (!levelBreak) {
Object prior = table.getValueAt(row - 1, 0);
Object current = table.getValueAt(row, 0);
levelBreak = !prior.equals(current);
}
comp.setBackground(levelBreak ? Color.BLUE : Color.WHITE);
}
return comp;
}
});
由于渲染器/渲染器组件已被所有表单元重复使用,因此必须为所有情况设置背景。
通常,JTable的TabelModel优于JTable的getValueAt来获取值,但是显然您既不对行进行排序也不对列进行重新排列。
对于可能安装的较旧渲染器
class MyCellRenderer extends DefaultTableCellRenderer {
private final TableCellRenderer old;
MyCellRenderer(TableCellRenderer old) {
this.old = old;
}
@Override
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
boolean levelBreak = row == 0;
if (!levelBreak) {
Object prior = table.getValueAt(row - 1, 0);
Object current = table.getValueAt(row, 0);
levelBreak = !prior.equals(current);
}
Component comp;
if (old != null) {
comp = old.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
} else {
comp = super.getTableCellRendererComponent(table,
value, isSelected, hasFocus, row, column);
}
comp.setBackground(levelBreak ? Color.BLUE : Color.WHITE);
return comp;
}
}
table.setDefaultRenderer(Object.class, new MyCellRenderer(table.getDefaultRenderer(Object.class));
答案 1 :(得分:1)
您需要创建和使用自定义TableCellRenderer
基本上,在此类中实现一个方法:
getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column)
我认为最简单的方法是创建一个扩展DefaultTableCellRendererComponent的新类,例如
class myRenderer extends DefaultTableCellRendererComponent {
public Component getTableCellRendererComponent(JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
Component c = super.getTableCellRendererComponent(...);
}
}
组件c是JLabel。只需调用setBackground(基于row
),就应该设置
答案 2 :(得分:0)
创建表时,我对内容一无所知,因为它已填充/行在运行时添加。
您不需要事先了解有关数据的任何信息。仅在将数据添加到TableModel之后,才完成JTable的呈现。
您在问题中链接的Table Row Rendering建议是您应该使用的方法。它显示了如何基于模型中的数据动态地进行渲染。
我发现的所有内容都使用固定检查,例如“如果单元格中的内容为“购买”,则将背景色设置为“绿色””
还有一个固定的支票:
您要做的就是比较两个值。是否从上一行检索一个值是否是硬编码的,对比较没有影响。
到目前为止,我必须使用自定义TableModel而不是DefaultTableModel
没有理由不能使用DefaultTableModel。实际上,Table Row Rendering
中的代码使用DefualtTableModel。使用的模型无关紧要。该模型所做的只是存储数据。然后,渲染过程将使用模型中的数据。
所以我的建议是:
Table Row Rendering
链接开始使用有效的演示代码。 首先了解基础知识。然后,担心从数据库动态添加数据。简化问题并一次解决一个步骤。
使用上面的所有建议进行简单的MRE:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class SSCCE extends JPanel
{
public SSCCE()
{
JTable myTable = new JTable()
{
@Override
public Class getColumnClass(int column)
{
return getValueAt(0, column).getClass();
}
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column)
{
Component c = super.prepareRenderer(renderer, row, column);
if (!isRowSelected(row))
{
if (row == 0)
c.setBackground( Color.BLUE );
else
{
Object previous = getModel().getValueAt(row - 1, 0);
Object current = getModel().getValueAt(row, 0);
c.setBackground( current.equals(previous) ? Color.WHITE : Color.BLUE );
}
}
return c;
}
};
myTable.setModel(new DefaultTableModel(
new Object[][] {
{"1000", 123},
{"1000", 234},
{"1001", 123},
{"1002", 123},
{"1002", 234},
{"1002", 345},
{"1003", 123},
{"1003", 234}
},
new String[] {
"ColumnA", "ColumnB"
}
));
setLayout( new BorderLayout() );
add(new JScrollPane(myTable));
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame("SSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new SSCCE());
frame.pack();
// frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args) throws Exception
{
java.awt.EventQueue.invokeLater( () -> createAndShowGUI() );
/*
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowGUI();
}
});
*/
}
}