删除JTable单元格截断

问题描述 投票:0回答:1

默认情况下,

JTable
会截断对于带有省略号的单元格来说太长的字符串。

我只想剪辑,就像在 macOS 的控制台应用程序中一样。

我已经看到了一个以前的答案,它允许通过覆盖

LabelUI
用其他东西替换省略号,但我不确定(1)如何使用
DefaultTableCellRenderer
来实现这个以及(2)我想要这个应用程序是跨平台的,所以我不认为我可以覆盖像
MetalUI
这样的特定类并期望它能够工作。

java swing
1个回答
0
投票

一个想法可能是将默认安装的渲染器放在

JScrollPane
中。这背后的原因是您不需要自定义
JTable
附带的渲染器(因此这听起来很有希望实现可移植性)。
JScrollPane
还确保默认渲染器(
JLabel
)永远不会获得比其首选尺寸更小的尺寸(即没有文本剪辑)。您只需隐藏
JScrollPane
的滚动条即可。

示例代码:

import java.awt.Component;
import java.awt.Font;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;

public class TableCellTrunc {
    
    public static class ScrollDecoratorRenderer implements TableCellRenderer {
        
        private final TableCellRenderer decorated;
        private final JScrollPane pane;

        public ScrollDecoratorRenderer(final TableCellRenderer decorated) {
            this.decorated = Objects.requireNonNull(decorated);
            pane = new JScrollPane();
            pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
            pane.setBorder(BorderFactory.createEmptyBorder());
        }
        
        @Override
        public Component getTableCellRendererComponent(final JTable table,
                                                       final Object value,
                                                       final boolean isSelected,
                                                       final boolean hasFocus,
                                                       final int row,
                                                       final int column) {
            pane.setViewportView(decorated.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column));
            return pane;
        }
    }
    
    private static Font enlargeFont(final Font font) {
        return font.deriveFont(font.getSize2D() * 1.2f);
    }
    
    public static void main(final String[] args) {
        SwingUtilities.invokeLater(() -> {
            
            /*try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            }
            catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException exception) {
                System.err.println("Failed to set system L&F.");
            }*/
            
            // Create data to fill the table:
            final int columnsCount = 3, rowsCount = 5;
            final String textExtension = " - huge but necessary text";
            final DefaultTableModel model = new DefaultTableModel();
            for (int columnIndex = 0; columnIndex < columnsCount; ++columnIndex)
                model.addColumn("Column " + columnIndex + textExtension);
            for (int rowIndex = 0; rowIndex < rowsCount; ++rowIndex) {
                final List<String> row = new ArrayList<>(columnsCount);
                for (int columnIndex = 0; columnIndex < columnsCount; ++columnIndex)
                    row.add("Column " + columnIndex + " - Row " + rowIndex + textExtension);
                model.addRow(row.toArray());
            }
            
            final JTable table = new JTable(model);
            final JTableHeader header = table.getTableHeader();

            // Apply custom renderer to header and/or table:
            header.setDefaultRenderer(new ScrollDecoratorRenderer(header.getDefaultRenderer()));
            table.setDefaultRenderer(Object.class, new ScrollDecoratorRenderer(table.getDefaultRenderer(Object.class)));

            // Enlarge font size for demonstration (optional):
            header.setFont(enlargeFont(header.getFont()));
            table.setFont(enlargeFont(table.getFont()));
            table.setRowHeight(header.getPreferredSize().height); // Simple way to accomodate larger font (only applicable in this case, and not intended as a general purpose solution).
            
            // Truncate bottom empty space of table (optional):
            table.setPreferredScrollableViewportSize(table.getPreferredSize());

            // Show result:
            final JFrame frame = new JFrame("Table cell trunc");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(new JScrollPane(table));
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

结果如下所示:

您也可以在标头中应用完全相同的原则(如示例代码所示)。这也针对 Windows 10 系统 L&F 进行了测试,显示出类似的行为。

但它有一些小限制,到目前为止我未能缓解:

  1. 有一个黑色垂直边框分隔列标题。如果您将表格缩小到需要截断列标题的程度,那么这些边框会由于某种原因(我不知道)变成白色,如下所示(红色圆圈中):
  2. 如果从示例代码中删除以下行:
    header.setFont(enlargeFont(header.getFont()));
    table.setFont(enlargeFont(table.getFont()));
    
    那么你还需要以下一项:
    table.setRowHeight(header.getPreferredSize().height);
    
    因为否则,对于默认的表格大小和字体,相对于单元格的底部(即每个单元格的文本似乎与单元格的底部稍微更对齐),可以在每个单元格的顶部观察到稍大的边距。

这个方法似乎需要一些调整,但它们又似乎与边界的小问题有关。

© www.soinside.com 2019 - 2024. All rights reserved.