How to change the color of a Jtable’s lines?

Asked

Viewed 1,239 times

1

I need the line color to change whenever the cell value is 0. However, all lines are being painted.

View with a simple Jtable

import javax.swing.JTable;

    public class View extends javax.swing.JFrame {

        private EstoqueActionListener listener;

        public View() {
            initComponents();
            this.listener = new EstoqueActionListener(this);
        }

        @SuppressWarnings("unchecked")
        // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
        private void initComponents() {

            jScrollPane1 = new javax.swing.JScrollPane();
            tableEstoque = new javax.swing.JTable();

            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

            tableEstoque.setModel(new javax.swing.table.DefaultTableModel(
                new Object [][] {
                    {null, null},
                    {null, null},
                    {null, null},
                    {null, null}
                },
                new String [] {
                    "PRODUTO", "STATUS"
                }
            ));
            jScrollPane1.setViewportView(tableEstoque);

            javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
            getContentPane().setLayout(layout);
            layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 752, Short.MAX_VALUE)
            );
            layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 295, javax.swing.GroupLayout.PREFERRED_SIZE)
            );

            pack();
        }// </editor-fold>                        


        public static void main(String args[]) {

            try {
                for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                    if ("Nimbus".equals(info.getName())) {
                        javax.swing.UIManager.setLookAndFeel(info.getClassName());
                        break;
                    }
                }
            } catch (ClassNotFoundException ex) {
                java.util.logging.Logger.getLogger(View.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
                java.util.logging.Logger.getLogger(View.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                java.util.logging.Logger.getLogger(View.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (javax.swing.UnsupportedLookAndFeelException ex) {
                java.util.logging.Logger.getLogger(View.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            }

            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new View().setVisible(true);
                }
            });
        }

        public JTable getTableEstoque() {
            return tableEstoque;
        }

        public void setTableEstoque(JTable tableEstoque) {
            this.tableEstoque = tableEstoque;
        }

        // Variables declaration - do not modify                     
        private javax.swing.JScrollPane jScrollPane1;
        private javax.swing.JTable tableEstoque;
        // End of variables declaration                   
    }

Class Estoquetablemodel extending Abstracttablemodel

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.table.AbstractTableModel;

public class EstoqueTableModel extends AbstractTableModel {

    List<Estoque> estoques;
    List<String> colunas = Arrays.asList("PRODUTO", "SALDO");

    public EstoqueTableModel() {
        Estoque e1 = new Estoque("ProdutoA", 10);
        Estoque e2 = new Estoque("ProdutoA", 10000);
        Estoque e3 = new Estoque("ProdutoA", 0);
        estoques = new ArrayList<>();
        estoques.add(e1);
        estoques.add(e2);
        estoques.add(e3);

    }

    @Override
    public int getRowCount() {
        return estoques.size();
    }

    @Override
    public int getColumnCount() {
        return colunas.size();
    }

    public int getColumnIndex(String coluna) {
        return colunas.indexOf(coluna);
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        Estoque e = estoques.get(rowIndex);
        String columnName = getColumnName(columnIndex);
        switch(columnName) {
            case "PRODUTO": return e.getNomeProduto();
            case "SALDO": return e.getSaldo();
        }
        return null;
    }

    @Override
    public String getColumnName(int column) {
        return colunas.get(column);
    }



    public List<Estoque> getEstoques() {
        return estoques;
    }

    public static class Estoque {
        private String nomeProduto;
        private int saldo;

        public Estoque(String nomeProduto, int saldo) {
            this.nomeProduto = nomeProduto;
            this.saldo = saldo;
        }

        public String getNomeProduto() {
            return nomeProduto;
        }

        public void setNomeProduto(String nomeProduto) {
            this.nomeProduto = nomeProduto;
        }

        public int getSaldo() {
            return saldo;
        }

        public void setSaldo(int saldo) {
            this.saldo = saldo;
        }
    }

}

Class that manages view events and starts Jtable data

import java.awt.Color;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;

public class EstoqueActionListener {

    private View viewEstoque;
    private EstoqueTableModel tableEstoque;

    public EstoqueActionListener(View viewEstoque) {
        this.viewEstoque = viewEstoque;
        startTable();
    }

    public void startTable() {
        tableEstoque = new EstoqueTableModel();
        if (tableEstoque.getEstoques() != null) {
            viewEstoque.getTableEstoque().setModel(tableEstoque);

            for (int i = 0; i < tableEstoque.getEstoques().size(); i++) {
                int cellValue = (int) tableEstoque.getValueAt(i, tableEstoque.getColumnIndex("SALDO"));
                if (cellValue == 0) { //SE 0, MUDE A COR
                    viewEstoque.getTableEstoque().setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
                        @Override
                        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                            final Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                            c.setBackground(Color.red);
                            c.setForeground(Color.white);
                            return c;
                        }
                    });
                }
            }
        }
    }
  • I even found a solution, but without a [mcve], there’s no way I can even test your code to see if it’ll work or vote reopening. Add this to the question to facilitate reopening.

  • I already have a solution, just waiting to reopen the question.

  • @diegofm found out why in that previous example nothing was being painted. Within the method I was passing my object to another class to align the cells. As a new instance of Defaulttablecellrenderer was created, I lost the characteristics of the previous one. This I have already fixed, however, all cells are painted instead of those specific ones. I await your solution.

1 answer

1


First you need to understand what the call below means:

viewEstoque.getTableEstoque().setDefaultRenderer(Object.class, new 
                                    DefaultTableCellRenderer(){..});

This method expects the type of cells in the table and a redenderer that cells will be applied with that type informed. Although Objectbe the mother class of all classes in java, there is a peculiarity in the functioning of swing renderers, where it applies certain rendering according to the types below:

  • Boolean - renders with a checkbox (checkbox).
  • Number - renders a right-aligned label.
  • Double, Float- the same as Number, but the "object-to-text" conversion is performed by an instance of NumberFormat(using the default number format for the current locale).
  • Date- renders a Label, with the "object-to-text" conversion performed by an instance of DateFormat(using a short style for date and time).
  • ImageIcon, Icon- rendered with a centralized label.
  • Object - rendered by a Label that displays the object’s string value.

As the value of your column saldo is of the numeric type, when rendering, java will take the type into consideration and apply the second option of the above list, completely ignoring what you defined in the Return.

To solve this, the simplest way is to define a right-to-right Renderer for the numeric column, rather than applying the entire table:

// no lugar do "1" é preciso informar o indice da coluna desejada
table.getColumnModel().getColumn(1).setCellRenderer(new SaldoTableRenderer());

In this case, I chose to create the class SaldoTableRenderer, and in it we need to save the default background and foreground values, because when the value is not zero, you can restore those values in the next cell:

public class SaldoTableRenderer extends DefaultTableCellRenderer {

    Color defaultBackground, defaultForeground;

    public SaldoTableRenderer() {
        this.defaultBackground = getBackground();
        this.defaultForeground = getForeground();
        setHorizontalAlignment(javax.swing.JLabel.RIGHT);
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
            int row, int column) {
        final Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

            Integer saldo = (int) value;

            if (saldo == 0) {
                c.setBackground(Color.red);
                c.setForeground(Color.white);
            }else{
                c.setBackground(defaultBackground);
                c.setForeground(defaultForeground);             
            }
            setText(saldo.toString());

        return c;
    }

}

And the result:

inserir a descrição da imagem aqui

If you want to see in practice before applying to your code, I made a testable example, just compile.


To overwrite the whole line, you need to overwrite the method prepareRenderer of the table, using the same logic as the previous answer:

    table = new JTable(new EstoqueTableModel()) {
        @Override
        public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {

            final Component c = super.prepareRenderer(renderer, row, column);

            Integer saldo = (int) table.getValueAt(row, 1);

            if (saldo <= 0) {
                c.setBackground(Color.red);
                c.setForeground(Color.white);
            } else {
                c.setBackground(table.getBackground());
                c.setForeground(table.getForeground());
            }
            return c;
        }
    };

References:

Concepts: Editors and Renderers (Documentation)

  • Really he painted only those that have the specific value. However, painted only the cell. How can I paint the whole Row?

  • @Marceloaugusto without modifying your tablemodel, there is no way to do this.

  • What would need to be modified?

  • I made a small change to your code. I took the balance amount from table.getValueAt(Row, 1). So I managed to paint.

  • @Marceloaugusto changing the column type to non-numeric and applying the cellrenderer to the whole table. Would have to validate the balance value by the column’s input as well.

  • @Marceloaugusto this change only in the answer code does not solve the problem. You have to change the type of the jump column too.

  • In the Columntablerenderer class I have added a parameter which is the column whose value is to be compared. So I can paint all the lines whose balance is 0. This solved my problem.

  • @Marceloaugusto the answer did not help you in any way? If yes, you can mark it as accepted by clicking on v the left. In this way, it serves as a reference for other people with similar problem :)

  • 1

    Sorry, man. After I solved the problem like I told you, I forgot. Thanks!

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.