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

如何设置JTextField实现超长文本从尾部截断显示?

解决JTextField文本超长时截断末尾、显示开头的问题

嘿,这个场景我太熟悉了!默认的JTextField在文本超长时确实会截断开头,只显示末尾,这在很多场景下都不符合需求。好在我们可以通过自定义它的文本视图来解决,而且完全不用手动计算文本长度——毕竟支持可变字号的话,手动计算简直是噩梦😅

核心思路

JTextField的文本绘制逻辑由PlainView类负责,默认实现是当文本宽度超过组件宽度时,从文本末尾开始绘制能容纳的部分。我们只需要自定义一个PlainView,修改它的绘制逻辑,改为从文本开头绘制、截断末尾即可。这个方案会自动适配当前字号,每次绘制都会用当前字体的FontMetrics计算宽度,完全不用我们手动维护。

完整代码实现

下面是一个可直接使用的自定义TextField类:

import javax.swing.*;
import javax.swing.text.*;
import java.awt.*;

public class LeadingTruncationTextField extends JTextField {
    public LeadingTruncationTextField() {
        super();
    }

    public LeadingTruncationTextField(String text) {
        super(text);
    }

    @Override
    protected Editor createDefaultEditor() {
        Editor editor = super.createDefaultEditor();
        // 替换默认的PlainView为我们自定义的视图
        editor.setView(new LeadingTruncationView(getDocument()));
        return editor;
    }

    // 自定义视图,实现开头显示、末尾截断
    private static class LeadingTruncationView extends PlainView {
        public LeadingTruncationView(Document doc) {
            super(doc);
        }

        @Override
        protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException {
            Container host = getContainer();
            if (!(host instanceof JTextField)) {
                return super.drawUnselectedText(g, x, y, p0, p1);
            }

            JTextField textField = (JTextField) host;
            FontMetrics metrics = textField.getFontMetrics(textField.getFont());
            int availableWidth = textField.getWidth() - textField.getInsets().left - textField.getInsets().right;
            String fullText = textField.getText();
            int fullTextWidth = metrics.stringWidth(fullText);

            // 文本能完全显示,直接调用父类方法
            if (fullTextWidth <= availableWidth) {
                return super.drawUnselectedText(g, x, y, p0, p1);
            }

            // 找到最大的字符数,使得开头到该位置的文本宽度不超过可用宽度
            int endIndex = fullText.length();
            while (metrics.stringWidth(fullText.substring(0, endIndex)) > availableWidth) {
                endIndex--;
            }

            // 绘制开头的有效部分
            g.drawString(fullText.substring(0, endIndex), x, y);
            return x + metrics.stringWidth(fullText.substring(0, endIndex));
        }

        // 可选:支持选中文本的截断显示(如果需要的话)
        @Override
        protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1) throws BadLocationException {
            // 逻辑和drawUnselectedText一致,这里简化处理
            return drawUnselectedText(g, x, y, p0, p1);
        }
    }
}

如何使用

直接用这个自定义类替换普通的JTextField即可,完全兼容原有API,比如:

public class TestDemo {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame frame = new JFrame("截断测试");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(300, 120);
            frame.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 20));

            // 创建自定义文本框,传入超长文本
            LeadingTruncationTextField textField = new LeadingTruncationTextField("这是一段用来测试的超长文本,看看是否会截断末尾显示开头部分");
            // 随便修改字号测试适配性
            textField.setFont(textField.getFont().deriveFont(18f));
            frame.add(textField);

            frame.setVisible(true);
        });
    }
}

额外优化建议

如果需要更友好的截断效果(比如添加省略号),可以在截断后的文本末尾加上...,只需要调整绘制的字符串即可,示例如下:

// 预留省略号的宽度,调整截断位置
String truncatedText = fullText.substring(0, endIndex - 3) + "...";
g.drawString(truncatedText, x, y);

内容的提问来源于stack exchange,提问作者Brian Knoblauch

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:27:19