在运行时设置JTable行的颜色

时间:2019-09-18 12:45:51

标签: java swing jtable

我的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,但是如何使用它呢?我发现的所有内容都使用固定检查,例如

  

如果单元格中的内容为“购买”,则将背景色设置为“绿色”

(例如herehere),但是在我的情况下,创建表时我对内容一无所知,因为表已填充/行在运行时添加。

我也找到了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"
    }
));

结果:

enter image description here

所需的结果(每个新的“ A列”值的背景为灰色):

enter image description here

替代结果(替代标记组的所有行):

enter image description here

3 个答案:

答案 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建议是您应该使用的方法。它显示了如何基于模型中的数据动态地进行渲染。

  

我发现的所有内容都使用固定检查,例如“如果单元格中的内容为“购买”,则将背景色设置为“绿色””

还有一个固定的支票:

  1. 您要获取当前行的数据
  2. 然后获取上一行的数据。
  3. 然后您将两个值进行比较并进行所需的突出显示。

您要做的就是比较两个值。是否从上一行检索一个值是否是硬编码的,对比较没有影响。

  

到目前为止,我必须使用自定义TableModel而不是DefaultTableModel

没有理由不能使用DefaultTableModel。实际上,Table Row Rendering中的代码使用DefualtTableModel。使用的模型无关紧要。该模型所做的只是存储数据。然后,渲染过程将使用模型中的数据。

所以我的建议是:

  1. Table Row Rendering链接开始使用有效的演示代码。
  2. 将硬编码数据更改为与真实数据相似。
  3. 然后添加自定义渲染逻辑

首先了解基础知识。然后,担心从数据库动态添加数据。简化问题并一次解决一个步骤。

使用上面的所有建议进行简单的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();
            }
        });
*/
    }
}