我不喜欢滚动条,因为它们很笨拙。我编写了一个自定义
JLabel
扩展,可以动态修剪每个 paint()
调用上的标签文本,并附加省略号
package StretchableLabel;
import lombok.SneakyThrows;
import javax.swing.*;
import java.awt.*;
public class StretchableLabel extends JLabel {
private String originalText;
public StretchableLabel(String text) {
super(text);
this.originalText = text;
}
@Override
public void setText(String text) {
this.originalText = text;
String displayedText = trimTextIfNecessary(text);
super.setText(displayedText);
}
private String trimTextIfNecessary(String text) {
if (getFont() == null) return text;
FontMetrics fontMetrics = getFontMetrics(getFont());
int textWidth = fontMetrics.stringWidth(text);
int parentWidth = getParent().getWidth();
if (textWidth > parentWidth) {
return trimText(text, parentWidth, fontMetrics);
} else {
return text;
}
}
private String trimText(String text, int parentWidth, FontMetrics fontMetrics) {
int textLimit = parentWidth / fontMetrics.charWidth('m');
return text.substring(0, textLimit) + "...";
}
@SneakyThrows
@Override
protected void paintComponent(Graphics g) {
String displayedText = trimTextIfNecessary(originalText);
super.setText(displayedText);
super.paintComponent(g);
}
}
package StretchableLabel;
import org.apache.commons.lang3.StringUtils;
import javax.swing.*;
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame("StretchableLabel Demo");
JPanel panel = new JPanel();
StretchableLabel label = new StretchableLabel((StringUtils.repeat("long label ", 20)));
panel.add(label);
frame.add(panel);
frame.pack();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
缺点:
getText()
应该返回与 setText()
(原始字符串)设置的相同值。但是, getText()
返回实际显示的文本,而 setText()
设置修剪后的文本。我无法覆盖 getText()
,因为它是由 paintComponent()
调用的——除非我检查调用者,这很棘手。像我一样拦截任何 setText()
调用非常重要,这样类的客户端就无法进行直接文本设置m
的宽度太保守了。通过在字符串上应用一些二分搜索算法来检查正确的子字符串长度会更精确(尽管从性能的角度来看这会更糟)如何正确实施我的想法?
您正在实现一项已经存在的功能。显然,基本/金属外观和感觉中存在一个错误,导致在未设置字体时计算出错误的尺寸。
有两个简单的解决方案
明确设置字体
public static void main(String[] args) {
JFrame frame = new JFrame("StretchableLabel Demo");
JLabel label = new JLabel("long label ".repeat(20));
label.setFont(new Font(Font.DIALOG, 0, 16));
frame.add(label, BorderLayout.CENTER);
frame.pack();
frame.setSize(frame.getWidth() >> 1, frame.getHeight());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
使用系统(即Windows)外观
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(ReflectiveOperationException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
JFrame frame = new JFrame("StretchableLabel Demo");
JLabel label = new JLabel("long label ".repeat(20));
frame.add(label, BorderLayout.CENTER);
frame.pack();
frame.setSize(frame.getWidth() >> 1, frame.getHeight());
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
}
在这两种情况下,您都可以获得预期的功能,免费剪切文本并附加省略号。请记住,您必须设置布局管理器,以便在空间不足时缩小
JLabel
。