如何以平滑的方式根据容器大小自动调整多个JLabel的字体大小?

我需要根据用于调整容器大小的缩放因子来调整多个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); } } 

图片: http : //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种方法的信息非常有用。

  1. 如果在多调用的基础上使用Coobird的代码有一些限制(例如在sizeChanged Listener或LayoutManager中)

  2. Trashgod的方法比Stanislav 的方法慢2到4倍(但它也被设计为填充OP在这个问题中提出的方向,所以不出意外。)

  3. 下面的代码改进了Stanislav的矩形方法 (每次从当前字体大小开始,而不是每次都恢复到MIN_FONT_SIZE),因此运行速度比该代码快20到50倍,特别是当窗口/字体很大时。

它还解决了该代码中的限制,该限制仅对位于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(); rx = 0; ry = 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); } }