我需要根据用于调整容器大小的缩放因子来调整多个JLabel的字体大小。为此,我将每个JLabel的字体设置为null,以便它们采用容器的字体。它有效,但也会产生奇怪的结果。
具体来说,文本似乎"滞后"于容器,有时甚至会被截断。我想避免这种行为。知道怎么做吗?
模拟行为的示例代码:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.geom.AffineTransform;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TextResize implements Runnable {
public static void main(String[] args) {
TextResize example = new TextResize();
SwingUtilities.invokeLater(example);
}
public void run() {
JFrame frame = new JFrame("JLabel Text Resize");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(800, 400));
Container container = frame.getContentPane();
container.setLayout(new BorderLayout());
final JPanel labelContainer = new JPanel(new GridBagLayout());
labelContainer.setBorder(BorderFactory.createLineBorder(Color.black));
//initial font
final Font textFont = new Font("Lucida Console", Font.PLAIN, 10).deriveFont(AffineTransform.getScaleInstance(1, 1));
labelContainer.setFont(textFont);
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.insets = new Insets(0, 10, 0, 10);
c.weightx = 1;
for (int i = 0; i < 5; i++) {
JLabel f = new JLabel("Text here with possibly looooooooong words");
f.setBorder(BorderFactory.createLineBorder(Color.green));
f.setFont(null);//take the font from parent
c.gridy = i;
labelContainer.add(f, c);
}
JSlider slider = new JSlider(0,50000,10000);
slider.addChangeListener(new ChangeListener() {
double containerWidth = labelContainer.getPreferredSize().getWidth();
double containerHeight = labelContainer.getPreferredSize().getHeight();
@Override
public void stateChanged(ChangeEvent ev) {
JSlider source = (JSlider) ev.getSource();
double scale = (double) (source.getValue() / 10000d);
//scaling the container
labelContainer.setSize((int) (containerWidth * scale), (int) (containerHeight * scale));
//adjusting the font: why does it 'lag' ? why the truncation at times?
Font newFont = textFont.deriveFont(AffineTransform.getScaleInstance(scale, scale));
labelContainer.setFont(newFont);
//print (font.getSize() does not change?)
System.out.println(scale + " " + newFont.getTransform() + newFont.getSize2D());
}
});
container.add(slider, BorderLayout.NORTH);
JPanel test = new JPanel();
test.setLayout(null);
labelContainer.setBounds(5, 5, labelContainer.getPreferredSize().width, labelContainer.getPreferredSize().height);
test.add(labelContainer);
container.add(test, BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
图片:https://i.stack.imgur.com/tZLOO.png
谢谢,
-s
您可以使用以下任何方法:
-
由@trashgod
-
由@StanislavL
-
由@coobird
我在某种程度上解决了添加的问题
@Override
protected void paintComponent(Graphics g) {
final Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
g2d.setRenderingHint(java.awt.RenderingHints.KEY_TEXT_ANTIALIASING, java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
super.paintComponent(g2d);
}
无论如何,谢谢。
如果性能速度是一个问题,那么您可能会发现以下关于MKorbel指出的3种方法的信息非常有用。
-
如果在多调用的基础上使用,Coobird的代码有一些限制(例如在sizeChanged Listener或LayoutManager中)
-
垃圾神的方法比斯坦尼斯拉夫的慢2到4倍(但它也被设计为按照OP在该问题中的要求双向填充区域,所以这并不意外。)
-
下面的代码改进了Stanislav的矩形方法(每次从当前字体大小开始,而不是每次恢复到MIN_font_size),因此运行速度比该代码快20到50倍,尤其是当窗口/font很大时。
它还解决了该代码中的一个限制,该代码仅有效地适用于位于0,0的标签(如给出的示例中所示)。下面的代码适用于面板上任何位置的多个标签。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
// Improved version of http://java-sl.com/tip_adapt_label_font_size.html
public class FontResizingLabel extends JLabel {
public static final int MIN_FONT_SIZE=3;
public static final int MAX_FONT_SIZE=240;
Graphics g;
int currFontSize = 0;
public FontResizingLabel(String text) {
super(text);
currFontSize = this.getFont().getSize();
init();
}
protected void init() {
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent e) {
adaptLabelFont(FontResizingLabel.this);
}
});
}
protected void adaptLabelFont(JLabel l) {
if (g==null) {
return;
}
currFontSize = this.getFont().getSize();
Rectangle r = l.getBounds();
r.x = 0;
r.y = 0;
int fontSize = Math.max(MIN_FONT_SIZE, currFontSize);
Font f = l.getFont();
Rectangle r1 = new Rectangle(getTextSize(l, l.getFont()));
while (!r.contains(r1)) {
fontSize --;
if (fontSize <= MIN_FONT_SIZE)
break;
r1 = new Rectangle(getTextSize(l, f.deriveFont(f.getStyle(), fontSize)));
}
Rectangle r2 = new Rectangle();
while (fontSize < MAX_FONT_SIZE) {
r2.setSize(getTextSize(l, f.deriveFont(f.getStyle(),fontSize+1)));
if (!r.contains(r2)) {
break;
}
fontSize++;
}
setFont(f.deriveFont(f.getStyle(),fontSize));
repaint();
}
private Dimension getTextSize(JLabel l, Font f) {
Dimension size = new Dimension();
//g.setFont(f); // superfluous.
FontMetrics fm = g.getFontMetrics(f);
size.width = fm.stringWidth(l.getText());
size.height = fm.getHeight();
return size;
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.g=g;
}
public static void main(String[] args) throws Exception {
FontResizingLabel label=new FontResizingLabel("Some text");
JFrame frame=new JFrame("Resize label font");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(label);
frame.setSize(300,300);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}