How to automatically adjust the font size of multiple JLabel based on container size in a smooth way?

I need to change the font size of several JLabels based on the scaling factor used to resize the container. To do this, I set the font of each JLabel to null to take the font of the container. It works, but it also gives strange results.

To be specific, the text appears to be โ€œlagging behindโ€ the container, and sometimes it even becomes truncated. I would like to avoid this behavior. Any idea how?

Example code that simulates behavior:

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); } } 

Photo: http://i.stack.imgur.com/tZLOO.png

Thank,

-s

+4
java fonts resize swing jlabel
Mar 21 '12 at 23:59
source share
3 answers

I solved the problem:

 @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); } 

Thank you anyway.

+2
Apr 26 '12 at 12:19
source share

You can use any of the following methods:

+6
Mar 22 '12 at 1:37
source share

If performance speed is a problem, then you can find the following information on the 3 methods pointed out by MKorbel above useful.

  • Coobird code has some limitations if they are used based on multitasking calls (for example, in Listen Lister or LayoutManager).

  • The Trashgod method is 2 and 4 times slower than Stanislav (but it is also intended to fill in the BOTH directions, as the OP asked in this question, therefore not unexpectedly.)

  • The code below improves the Stanislav rectangle method (starting with the current font size each and not returning to MIN_FONT_SIZE each time) and thus works 20-50 times faster than this code, especially when the window / font size is large.

It also addresses the restriction in this code, which only works effectively for tags located at 0.0 (as in the example here). The code below works for multiple labels in the panel and anywhere.

 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); } } 
+1
Jun 10 '15 at 1:19
source share



All Articles