4

my question is, how to solve following problem:

If i click on a cell in a JTable, i want to change its background. If i release the mousebutton, i want the background change back to normal color.

Is that possible?

Greetings ayk

ayk
  • 1,330
  • 2
  • 15
  • 24

3 Answers3

5

For doing it in the visual realm you need

  • a MouseListener which sets some state in cell-coordinates on pressed and resets that state on released
  • a PropertyChangeListener listeneng to that state which repaints the cell on change
  • a custom renderer which sets a custom background for the cell that is flagged

some code for the listeners

    MouseListener l = new MouseAdapter() {

        /** 
         * @inherited <p>
         */
        @Override
        public void mousePressed(MouseEvent e) {
            JTable table = (JTable) e.getComponent();
            int col = table.columnAtPoint(e.getPoint());
            int row = table.rowAtPoint(e.getPoint());
            if (col < 0 || row < 0) {
                table.putClientProperty("pressedCell", null);
            } else {
                table.putClientProperty("pressedCell", new Point(col, row));
            }
        }

        /** 
         * @inherited <p>
         */
        @Override
        public void mouseReleased(MouseEvent e) {
            ((JTable) e.getComponent()).putClientProperty("pressedCell", null);
        }

    };
    table.addMouseListener(l);
    PropertyChangeListener property = new PropertyChangeListener() {

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            JTable table = (JTable) evt.getSource();
            Point cell = evt.getNewValue() != null ? 
                    (Point) evt.getNewValue() : (Point) evt.getOldValue();
            if (cell != null) table.repaint(table.getCellRect(cell.y, cell.x, false));        
        }

    };
    table.addPropertyChangeListener("pressedCell", property);

Highlighting the cell in SwingX (cant resist :-)

    HighlightPredicate predicate = new HighlightPredicate() {

        @Override
        public boolean isHighlighted(Component renderer, ComponentAdapter adapter) {
            Point p = (Point) adapter.getComponent().getClientProperty("pressedCell");
            return p != null && p.x == adapter.column && p.y == adapter.row;

        }
    };
    table.addHighlighter(new ColorHighlighter(predicate, Color.YELLOW, null, Color.YELLOW, null));

For core Swing, either implement a custom TableCellRenderer or subclass the JTable and override prepareRenderer to set the background color according to the cell flag, as explained in Rob's Table Row Rendering

kleopatra
  • 51,061
  • 28
  • 99
  • 211
  • why complicated things with addon another Listener to the JTable (and sooo, very heavy) and MouseListener, which generated more that 1.000,- events per second, 1) isn't that contraproductive, then maybe Renderer would be more lightwieght aka Listener, 2) agreed is there non-compactible HightLighter then there another Listener maybe doesn't generated expected events.. – mKorbel Sep 01 '11 at 21:39
  • +1 : you are right. This is was the user was looking for. Interesting too, I never heard ColorHighlighter before – Heisenbug Sep 02 '11 at 08:07
  • @Overbose it's a SwingX Highlighter :-) – kleopatra Sep 02 '11 at 08:42
  • (darn, thought I had sent this comment an hour ago, sometimes this systems freaks me ..."wait 15 seconds for the next comment" ) @mKorbel because the seemingly simple solution (as you and Overdose suggested) doesn't fulfill the requirement, so it's not a solution at all :-) – kleopatra Sep 02 '11 at 08:45
  • @kleopatra 1) `systems freaks me` - FW issue 2) can you be little bit concrete, beacuse fulfill here, fulfill there, without clear --> :-), 3) really only way is implements MouseAdapter & Point – mKorbel Sep 02 '11 at 09:01
4

in your renderer you have to overide hasFocus

for example

enter image description here

import java.awt.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;

public class TableRenderer extends JFrame {

    private static final long serialVersionUID = 1L;
    private JTable table;
    private String[] columnNames = {"Date", "String", "Centered", "Integer", "Boolean"};
    private Object[][] data = {
        {new Date(), "A", "A", new Integer(1), true},
        {new Date(), "B", "B", new Integer(2), false},
        {new Date(), "C", "C", new Integer(10), null},
        {new Date(), "D", "D", new Integer(4), false}
    };

    public TableRenderer() {
        DefaultTableModel model = new DefaultTableModel(data, columnNames);
        table = new JTable(model) {

            private static final long serialVersionUID = 1L;
            //  Returning the Class of each column will allow different
            //  renderers to be used based on Class

            @Override
            public Class getColumnClass(int column) {
                return getValueAt(0, column).getClass();
            }
        };
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        JScrollPane scrollPane = new JScrollPane(table);
        getContentPane().add(scrollPane);

        //  Override default renderer on a specific Class
        TableCellRenderer colorRenderer = new ColorRenderer();
        table.setDefaultRenderer(String.class, colorRenderer);

        //  Override default renderer for a specific column
        DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
        centerRenderer.setHorizontalAlignment(JLabel.CENTER);
        table.getColumnModel().getColumn(2).setCellRenderer(centerRenderer);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                TableRenderer frame = new TableRenderer();
                frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    /*
     **  Color the focused cell
     */
    private class ColorRenderer extends DefaultTableCellRenderer {

        private static final long serialVersionUID = 1L;

        @Override
        public Component getTableCellRendererComponent(
                JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            if (hasFocus) {
                setBackground(Color.cyan);
            } else if (isSelected) {
                setBackground(table.getSelectionBackground());
            } else {
                setBackground(table.getBackground());
            }
            return this;
        }
    }
}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • you have a small example if i use defaultcellrenderer? – ayk Aug 31 '11 at 19:23
  • +1: another way rather than ListSelectionModel. I don't know if it's the best solution anyway. – Heisenbug Aug 31 '11 at 19:26
  • @0verbose hmmm just I'm sure that this is short way, +1, but another question from your history, is there some news about your non-sortable rows in the JTable, have you any progress with that???, for hint that you posted here is required implements this one http://tips4java.wordpress.com/2008/10/20/table-select-all-editor/ – mKorbel Aug 31 '11 at 19:44
  • @mKorbel: I solved with a workaround and I don't remember how :) . I'm looking at the code right know and I can't find it. – Heisenbug Aug 31 '11 at 19:58
  • Thank you for the code, but this is not exactly what im looking for. Maybe my expanation was not clear enough. What i need is somethink like a "Button" behaviour. If i click the cell and hold the mousebutton, the color should change to cyan for example, but if i release the button, it shell change back. Greetings ayk – ayk Sep 01 '11 at 04:55
  • -1 doesn't fulfil requirement: you simply show how to change the color of the focused cell, which the cell trivially becomes when clicking on it (and by other ways, f.i. navigating with the cursor keys) – kleopatra Sep 02 '11 at 07:55
  • @kleopatra yes // Override default renderer on a specific Class `table.setDefaultRenderer(String.class, colorRenderer);`, is valid only for one TableColumn – mKorbel Sep 02 '11 at 08:19
  • no, your approach simple doesn't fulfill the requirement ... doesn't matter which renderer you use, the mouse-related logic is missing – kleopatra Sep 02 '11 at 08:46
1

Yes it is possible. Use a custom ListSelectionModel and set your JTable to use that : setSelectionModel().

Here's an example.

Heisenbug
  • 38,762
  • 28
  • 132
  • 190