Java JTable disable single cell selection border highlight
Asked Answered
N

3

6

I have a JTable with three columns in each row, see the image:

enter image description here

For some reason depending on the column i select i get the little dark blue border around it (V140116554) in the image above.

I currently use this to select the entire row:

vTable.setRowSelectionAllowed(true);

How can i disable this?

EDIT:

Added a class:

public class VisitorRenderer extends DefaultTableCellRenderer {
    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 
        setBorder(noFocusBorder);
        return this;
    }
} 

And added it:

vTable.setDefaultRenderer(String.class, new VisitorRenderer());

But still get the border

Nonsmoker answered 14/9, 2013 at 11:12 Comment(0)
H
15

The TableCellRenderer is responsible for drawing the focus rectangle around the currently focused cell. You need to supply your own renderer that is capable of either overriding this feature or providing its own...

For example;

public class MyRenderer extends DefaultTableCellRenderer {

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 
        setBorder(noFocusBorder);
        return this;
    }

}

This uses the DefaultTableCellRenderer as the base renderer and sets the component's Border to noFocusBorder which is defined in DefaultTableCellRenderer as a EmptyBorder

You will then need to set this renderer as the default renderer for the effected columns. Check out How to use tables for more details

Update with example

Works fine for me...

enter image description here

import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;

public class TableRenderer {

    public static void main(String[] args) {
        new TableRenderer();
    }

    public TableRenderer() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                DefaultTableModel model = new DefaultTableModel(new Object[][]{{"", "One"}, {"", "Two"}}, new Object[]{"Check", "Vistor"}) {
                    @Override
                    public Class<?> getColumnClass(int columnIndex) {
                        return String.class;
                    }
                };

                JTable table = new JTable(model);
                table.setRowSelectionAllowed(true);
                table.setShowGrid(false);
                table.setDefaultRenderer(String.class, new VisitorRenderer());

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new JScrollPane(table));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class VisitorRenderer extends DefaultTableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            setBorder(noFocusBorder);
            return this;
        }
    }
}

And just to be sure, I changed setBorder(noFocusBorder); to...

if (hasFocus) {
    setBorder(new LineBorder(Color.RED));
}

enter image description here

From the looks of things, the visitor column class type isn't being reported as String by the TableModel...

Updated with proxy renderer concept

Because you want to remove the focus border from every cell. You have three choices...

  1. Write a custom cell renderer for every possibility of Class type you might need for your table. This can time consuming and repeats a lot of code to achieve only a small effect.
  2. Do nothing a live with it...
  3. Use a "proxy" renderer. This is a renderer that uses another TableCellRenderer to perform the actual rendering process, but applies some minor changes to the result, for example, remove the border...

...

public static class ProxyCellRenderer implements TableCellRenderer {

    protected static final Border DEFAULT_BORDER = new EmptyBorder(1, 1, 1, 1);
    private TableCellRenderer renderer;

    public ProxyCellRenderer(TableCellRenderer renderer) {
        this.renderer = renderer;
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
        Component comp = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
        if (comp instanceof JComponent) {
            ((JComponent)comp).setBorder(DEFAULT_BORDER);
        }
        return comp;
    }        
}

Instead of doing something like...

table.setDefaultRenderer(String.class, new VisitorRenderer());

Which we did before, we would do this instead...

table.setDefaultRenderer(String.class, 
    new ProxyCellRenderer(table.getDefaultRenderer(String.class)));

This means we can take advantage of the what ever default renderer is already available without knowing what that might be, but also supply our own custom requirements to it...

Heribertoheringer answered 14/9, 2013 at 11:17 Comment(8)
Works just fine for me. See updates. I suspect that the visitor column isn't being reported as String.class by your TableModel...Heribertoheringer
That was the problem, however i have 2 columns that are Icon.class now the middle column does not display a border but the first and last still do cause they are Icon.ClassNonsmoker
You'll have to do the same thing for each type. A sneaky way would be to create a ProxyCellRenderer which took another TableCellRenderer, used it to as the mechanism to renderer the given cell contents, but set the border to a EmptyBorder, this way you could just get the default renderers that are in use and feed them through this proxy renderer instead...Heribertoheringer
Not quite sure i follow :/Nonsmoker
Sorry, it was late and I was heading off to bed, so it probably came out as babble. See updateHeribertoheringer
@mathguy54 You need to provide a runnable example that demonstrates your problem, as both examples work just fine for me. Maybe you need to raise your own questions (quoting this question/answer as starting point)Heribertoheringer
You might want to check the size of existing border before making your EmptyBorder. setBorder(new EmptyBorder(getBorder().getBorderInsets(this))); else you may get strange visual results.These
@These A better solution might be to use a CompoundBorder, assuming the cell had an existing border to start withHeribertoheringer
E
3

Instead of creating your own TableCellRenderer you could also do:

@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {
    Component c = super.prepareRenderer(renderer, row, col);
        
    if (c instanceof JComponent)
          ((JComponent)c).setBorder(new EmptyBorder(1, 1, 1, 1));
    return c;
}

Ecg answered 10/2, 2021 at 20:56 Comment(1)
very useful. setBorder(null) also works.Camembert
E
1

If you have absolutely no need for the border on any cell in that table, just apply MyRenderer to all cells, regardless of class. You can do it like this:

table.setDefaultRenderer(Object.class, new MyRenderer());

Evieevil answered 27/2, 2014 at 13:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.