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

mKorbel
  • 109,525
  • 20
  • 134
  • 319
Alosyius
  • 8,771
  • 26
  • 76
  • 120

3 Answers3

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...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Works just fine for me. See updates. I suspect that the visitor column isn't being reported as `String.class` by your `TableModel`... – MadProgrammer Sep 14 '13 at 11:35
  • 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.Class – Alosyius Sep 14 '13 at 11:43
  • 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... – MadProgrammer Sep 14 '13 at 11:59
  • Not quite sure i follow :/ – Alosyius Sep 14 '13 at 12:04
  • Sorry, it was late and I was heading off to bed, so it probably came out as babble. See update – MadProgrammer Sep 14 '13 at 21:40
  • @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) – MadProgrammer Jun 05 '14 at 23:53
  • 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. – Orwellophile Oct 05 '20 at 20:45
  • @Orwellophile A better solution might be to use a `CompoundBorder`, assuming the cell had an existing border to start with – MadProgrammer Oct 05 '20 at 21:06
2

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;
}

Locutus
  • 444
  • 4
  • 12
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());

Pranx
  • 11
  • 3