2

I want to create a JTable and color its cells permanently by the click of a button (pretty like excel in coloring cells).So far, every cell I select, it gets in an ArrayList<Cell>.

First of all, I want for every cell in the list to be colored permanently when I click the button (this is the difference from code I found). Shoud I have to use a statememnt like this table.getColumnModel().getColumn(column).setCellRenderer(this); ?

It is a compilable code and if you debug it, you will see that when the button is clicked, I cannot access getTableCellRendererComponent() method. Why is that happening? I would appreciate if you could tell me your opinions.

(Note: it's a reproduce of a huge program, so it's a little big messy and hard-coded in some places. Couldn't make it smaller for what I want to solve).

Class ColorSelectedTableCells.java

public class ColorSelectedTableCells extends JPanel {
   private JButton btn = new JButton("color cells");
   private MyCellRenderer myCellRenderer = new MyCellRenderer();
   public static final Object[][] DATA = new Object[3][3];
   public static final String[] COLS = {"A", "B", "C"};
   private static final int PREF_WIDTH = 400;
   private static final int PREF_HEIGHT = 300;
   private static CellSelectionSet cellSelectionSet = new CellSelectionSet();

   private JTable table = new JTable(DATA,COLS){
       @Override
       public boolean isCellEditable(int row, int column) {return false;}

       @Override
       public boolean isCellSelected(int row, int column) {
          if (cellSelectionSet.containsOneOrLess()) {
            return super.isCellSelected(row, column);
          }
            return cellSelectionSet.contains(row, column);
        }

        @Override
        public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) {
          super.changeSelection(rowIndex, columnIndex, toggle, extend);
          if (toggle) {
            cellSelectionSet.add(rowIndex, columnIndex);
          } 
          else {
            if (extend) {
              cellSelectionSet.add(rowIndex, columnIndex);
            } 
            else {
              cellSelectionSet.clear();
              cellSelectionSet.add(rowIndex, columnIndex);
            }
          }
        }   
      };

 public ColorSelectedTableCells() {
  table.setDefaultRenderer(Integer.class, myCellRenderer);
  table.setCellSelectionEnabled(true);
  table.setColumnSelectionAllowed(false);
  table.setRowSelectionAllowed(false);

  JScrollPane scrollPane = new JScrollPane(table, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
  JPanel btnPanel = new JPanel();
  btnPanel.add(btn);

  setLayout(new BorderLayout());
  add(scrollPane, BorderLayout.CENTER);
  add(btnPanel, BorderLayout.SOUTH);

  btn.addActionListener(new ActionListener() {
     @Override
     public void actionPerformed(ActionEvent e) {
        myCellRenderer.setShowSelected(true);
        table.repaint();
     }
  });
}

@Override
public Dimension getPreferredSize() {
   return new Dimension(PREF_WIDTH, PREF_HEIGHT);
}

private static void createAndShowUI() {
  JFrame frame = new JFrame();
  frame.getContentPane().add(new ColorSelectedTableCells());
  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  frame.pack();
  frame.setLocationRelativeTo(null);
  frame.setVisible(true);
}

public static void main(String[] args) {
  java.awt.EventQueue.invokeLater(new Runnable() {
     public void run() {
        createAndShowUI();
     }
  });
}

Class MyCellRenderer.java

private static class MyCellRenderer extends DefaultTableCellRenderer {
  private boolean showSelected = false;
  private byte colorSwitcher;

  public void setShowSelected(boolean showSelected) {
     this.showSelected = showSelected;
  }

  public void setColorSwitcher(byte colorSwitcher){
      this.colorSwitcher = colorSwitcher;
  }

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

      if(showSelected && table.isCellSelected(row, column)){
        superComponent.setBackground(Color.GREEN);
      }
      else if (table.isCellSelected(row, column)){
        superComponent.setBackground(table.getSelectionBackground());
      }
      else {
        superComponent.setBackground(table.getBackground());
      }
       return superComponent;
    }
  }
}

Class cellSelectionSet.java

  public class CellSelectionSet {
  private List<Cell> cells = new ArrayList<>();

  public void add(int r, int c) {
    if (!contains(r, c)) {
        cells.add(new Cell(r, c));
    }
  }

  public boolean containsOneOrLess() {
    return cells.size() <= 1;
  }

  public boolean contains(int r, int c) {
    for (Cell cell : cells) {
        if (cell.is(r, c)) {
            return true;
        }
    }
    return false;
  }

  public Cell getElementAt(int i){
    return cells.get(i);
  }

  public int getSize(){
    return this.cells.size();
  }

  public void clear() {
    cells.clear();
    System.out.println("CellSelectionSet cleared.");
  }  
}

Class Cell.java

public class Cell {
  private int row, column;

  public Cell(int row, int column){
    this.row = row;
    this.column = column;
  }

  public boolean is(int r, int c) {
    return row == r && column == c;
  }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
Vassilis De
  • 363
  • 1
  • 3
  • 21

1 Answers1

2

Main problem:

table.setDefaultRenderer(Integer.class, myCellRenderer);

Should be

table.setDefaultRenderer(Object.class, myCellRenderer);

This will get your cells to change color. But then you have a the problem where after you press the button, each cell you select automatically changes color, because of the showSelected property is set to true. Who knows, maybe that's how you want it.

Also another problem is with the cells staying the selection color. The problem if with your check statement

if(showSelected && table.isCellSelected(row, column)){

Once you make more selections, the original selections is cleared. A fix would be to check against the CellSelectionSet to see if it contains the cell, but also to check if it's newly selected or not. Something like

if (cellSelectionSet.contains(row, column)
                  && !cellSelectionSet.getCellAt(row, column).isNewlySelected())

I added a method getCellAt to your CellSelectionSet

public Cell getCellAt(int row, int column) {
    Cell c = null;
    for (Cell cell : cells) {
        if (cell.is(row, column)) {
            c = cell;
        }
    }
    return c;
}

And also a flag in the Cell class to check if it's newlySelected. The default is true

class Cell {

    private boolean newlySelected = true;

    public boolean isNewlySelected() {
        return newlySelected;
    }

    public void setNewlySelected(boolean newlySelected) {
        this.newlySelected = newlySelected;
    }
}

When you first add the cell, it will be newly selected and will not render the different color, as it doesn't pass the check

!cellSelectionSet.getCellAt(row, column).isNewlySelected()

But when you press the button, you iterate through the list and set all the cell newlySelected to false.

public void actionPerformed(ActionEvent e) {
    //myCellRenderer.setShowSelected(true);
    for (int i = 0; i < cellSelectionSet.getSize(); i++) {
        cellSelectionSet.getElementAt(i).setNewlySelected(false);
    }
    table.repaint();
}
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • You save me! But now I have another problem..The selected cells do change color, but when I select another cell, all previour return to white ("unselected"). Can you please tell me how am I goind to fix that? – Vassilis De Oct 02 '14 at 16:19
  • See my update. I think It works like how you want not – Paul Samsotha Oct 02 '14 at 16:33
  • Cells still return to "unselected" when I select another cell..should I change the flag inside `if (cellSelectionSet.contains(row, column)&& !cellSelectionSet.getCellAt(row, column).isNewlySelected())` statement? – Vassilis De Oct 02 '14 at 16:46
  • It works fine for me. I just switch your first if statement for mine. I left the else if and else – Paul Samsotha Oct 02 '14 at 16:48
  • I checked my code again but still nothing. Apparently there is something I don't see! Thank you my friend! – Vassilis De Oct 02 '14 at 16:56
  • Ah, it's because of `cellSelectionSet.clear();` in your `changeSelection` method of the table. I guess whoever implemented this wanted this effect, as it's the default behavior of the table. You can comment that out, and it will work. But also doing this allows for multiple selection without having to hold shift/ctrl. Not sure if that's what you want. If not, then you will have to have a copy of the `CellSelectionSet` inside the renderer, and whenever you add more cells, just add the new cells from the original set to the renderer's set – Paul Samsotha Oct 02 '14 at 17:03
  • Yes, I commented it out and now works!! Once more, thank you a lot! I will copy the List and everything is OK! – Vassilis De Oct 02 '14 at 17:18