You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调整JTable列宽适配内容却显示省略号,如何精准实现?

问题原因与解决方案

你遇到的不是Swing Bug,而是计算列宽时忽略了单元格/表头的内边距(Insets)。FontMetrics只计算纯文本的宽度,但Swing单元格默认带有左右内边距,你设置的列宽刚好等于文本宽度,加上内边距后实际可用空间不足,导致文本被截断显示省略号。

解决思路

计算列宽时,需要额外加上单元格和表头渲染器的左右内边距,确保列宽能容纳文本+内边距的总宽度;同时修正原代码中的布局错误,保证初始化状态下列宽正确。

修改后的完整代码

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Insets;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumnModel;

public class Scrollable_Table_Example extends JFrame {

    private static final long serialVersionUID = 1L;

    private JPanel _panel;

    private JTextArea _text;
    private JTable _table;
    private DefaultTableModel _model;
    private JScrollPane _scroll;

    public static void main(String[] args) {
        Scrollable_Table_Example app = new Scrollable_Table_Example();
        app.setVisible(true);
    }   

    public Scrollable_Table_Example() {
        _panel = new JPanel(new BorderLayout());
        setPreferredSize(new Dimension(300, 500));
 
        _text = new JTextArea(300, 300);
        _text.setEditable(false);

        JScrollPane areaScrollPane = new JScrollPane(_text);
        areaScrollPane.setPreferredSize(new Dimension(250, 250));

        areaScrollPane.setHorizontalScrollBarPolicy(
                JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        areaScrollPane.setVerticalScrollBarPolicy(
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);

        areaScrollPane.setViewportView(_text); // 修正原add方法的错误,改用setViewportView设置滚动面板内容
        _panel.add(areaScrollPane, BorderLayout.NORTH);

        _model = new DefaultTableModel();
        _model.addColumn("Type");
        _model.addColumn("Schema");
        _model.addColumn("Module Name");
        _model.addColumn("Path");

        _table = new JTable();
        _table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
        _table.getTableHeader().setResizingAllowed(false);
        _table.getTableHeader().setReorderingAllowed(false);
        _table.setModel(_model);

        addComponentListener(new ComponentAdapter() {
            public void componentResized(ComponentEvent e) {
                resizeColumnWidth(_table);
            }
        });
 
        for(int i = 0; i < 20; i++) {
            Vector<String> r  = new Vector<String>();
            r.addElement("TABLE");
            r.addElement("dbo");
            r.addElement("Policy");
            r.addElement("OBJECTS -> INSURANCE -> Policy");
            _model.addRow(r);
        }

        _scroll = new JScrollPane(_table);
        _panel.add(_scroll, BorderLayout.CENTER);
        add(_panel);
        pack();
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setLocationRelativeTo(null);
        resizeColumnWidth(_table); // 初始化时调用一次,确保初始列宽正确
    }   

    public static void resizeColumnWidth(JTable table) {
        final TableColumnModel columnModel = table.getColumnModel();
        FontMetrics fontMetrics = table.getFontMetrics(table.getFont());

        for (int column = 0; column < table.getColumnCount(); column++) {
            String headerValue = columnModel.getColumn(column).getHeaderValue().toString();
            
            // 获取表头渲染器的内边距,计算表头总宽度
            TableCellRenderer headerRenderer = table.getTableHeader().getDefaultRenderer();
            Component headerComp = headerRenderer.getTableCellRendererComponent(table, headerValue, false, false, 0, column);
            Insets headerInsets = headerComp.getInsets();
            int headerWidth = fontMetrics.stringWidth(headerValue) + headerInsets.left + headerInsets.right;

            // 获取单元格渲染器的内边距,计算内容所需额外宽度
            TableCellRenderer cellRenderer = table.getDefaultRenderer(table.getColumnClass(column));
            Component cellComp = cellRenderer.getTableCellRendererComponent(table, "", false, false, 0, column);
            Insets cellInsets = cellComp.getInsets();
            int cellExtraWidth = cellInsets.left + cellInsets.right;

            int width = headerWidth;

            // 计算每一行内容的总宽度,取最大值
            for (int row = 0; row < table.getRowCount(); row++) {
                String columnValue = table.getModel().getValueAt(row, column).toString();
                int columnValueWidth = fontMetrics.stringWidth(columnValue) + cellExtraWidth;
                width = Math.max(width, columnValueWidth);
            }
            // 加2像素缓冲避免极端情况截断
            columnModel.getColumn(column).setPreferredWidth(width + 2);
        }

        int parentWidth = table.getParent().getSize().width;
        int tableWidth = table.getPreferredSize().width;
        
        if(parentWidth > tableWidth) {
            int diff = parentWidth - tableWidth;
            int newWidth = columnModel.getColumn(3).getPreferredWidth() + diff;
            columnModel.getColumn(3).setPreferredWidth(newWidth);
        }
    }
}

关键修正说明

  1. 内边距计算:分别获取表头和单元格渲染器的内边距,将其加到文本宽度上,确保列宽足够容纳所有内容。
  2. 滚动面板内容设置:原代码用add方法给滚动面板加内容是错误的,改用setViewportView符合Swing规范。
  3. 初始化调用:窗口初始化完成后调用一次列宽调整,避免初始状态下列宽不正确。

内容的提问来源于stack exchange,提问作者Newbie Guest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 04:55:29