Java JTable 如何禁用单元格选择边框高亮?

6

我有一个JTable,每行有三列,如下图所示:

enter image description here

由于某种原因,当我选择不同的列时,会在其周围出现深蓝色边框(如上图中的V140116554)。

我目前使用以下代码来选择整行:

vTable.setRowSelectionAllowed(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;
    }
} 

并添加它:

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

但仍然获得边框。
3个回答

15
TableCellRenderer 负责在当前聚焦的单元格周围绘制聚焦矩形。您需要提供自己的渲染器,以便覆盖此功能或提供自定义实现...。
例如:
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;
    }

}

这里使用了DefaultTableCellRenderer作为基本渲染器,并将组件的Border设置为noFocusBorder,该值在DefaultTableCellRenderer中定义为EmptyBorder

然后需要将此渲染器设置为所需列的默认渲染器。详见如何使用表格

示例更新

对我来说工作得很好...

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

为了确保,我将setBorder(noFocusBorder);更改为...

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

在此输入图片描述

从现有的情况来看,访客列的类类型在TableModel中没有被报告为String...

使用代理渲染器概念进行更新

因为您希望从每个单元格中移除焦点边框。您有三种选择...

  1. 为可能用于表格的每种Class类型编写自定义单元格渲染器。这可能很耗时,并且重复了大量代码以实现仅获得小的效果。
  2. 不做任何处理,并接受它的存在...
  3. 使用“代理”渲染器。这是一种渲染器,它使用另一个TableCellRenderer执行实际的渲染过程,但对结果应用一些微小的更改,例如删除边框...

...

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

不要像这样做...

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

我们以前做过的,现在将会改为这样做...

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

这意味着我们可以利用已经可用的任何默认渲染器,而无需知道它是什么,但也可以向其提供自己的自定义要求...


对我来说完全正常。请查看更新。我怀疑您的TableModel没有将访客列报告为String.class... - MadProgrammer
那就是问题所在了,但是我有两列现在都是Icon.class,中间的一列没有显示边框,但是第一列和最后一列仍然会因为它们是Icon.Class而显示边框。 - Alosyius
你需要为每种类型都做同样的事情。一个巧妙的方法是创建一个ProxyCellRenderer,它接受另一个TableCellRenderer,用它作为呈现给定单元格内容的机制,但将边框设置为EmptyBorder,这样你就可以获取正在使用的默认渲染器,并将它们通过这个代理渲染器传递。 - MadProgrammer
我不太确定我理解了:/ - Alosyius
抱歉,当时已经很晚了,我要去睡觉了,所以可能说得有点含糊不清。请看更新。 - MadProgrammer
显示剩余3条评论

2

您可以不创建自己的TableCellRenderer,而是采用以下方法:

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


1
如果您对表格中任何单元格的边框都没有需求,只需将MyRenderer应用于所有单元格,而不考虑类别。您可以这样做: table.setDefaultRenderer(Object.class, new MyRenderer());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接