如何设置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
相关产品推荐
相关产品推荐

