【问题标题】:How to auto-adjust font size of multiple JLabel based on container size in a smooth way?如何平滑地根据容器大小自动调整多个 JLabel 的字体大小?
【发布时间】:2012-03-21 23:59:44
【问题描述】:

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

【问题讨论】:

    标签: java swing fonts resize jlabel


    【解决方案1】:

    您可以使用以下任何一种方法:

    【讨论】:

    • 谢谢,呵呵,(camickr 和 darryl burke)还有另外两个解决方法
    • 谢谢,事实上我已经尝试过其中一些示例:它们似乎不适用于我的 sn-p。这是布局问题吗?
    • GridBoxLayout 是绝对布局吗?
    • @fusio 不是,但你的 labes 是 labelContainer.setBounds(5, 5, ...) 的地方,这个代码线正是关于 AbsoluteLayout,
    • 我尝试在不使用任何绝对布局和 BoxLayout 而不是 BoxGridLayout 的情况下修改 sn-p。这些示例仍然无法正常工作..
    【解决方案2】:

    我解决了添加的问题:

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

    还是谢谢。

    【讨论】:

    • 顺便说一句:使用 JtextField,使用 KEY_FRACTIONALMETRICS 缩放时插入符号出现错误。修复它:jTextField.getDocument().putProperty("ZOOM_FACTOR", scale);
    【解决方案3】:

    如果性能速度是一个问题,那么您可能会发现以下有关 MKorbel 指出的 3 种方法的信息很有用。

    1. Coobird's code 如果在多调用基础上使用(例如在 sizeChanged 侦听器或 LayoutManager 中)会有一些限制

    2. Trashgod's method 比 Stanislav 慢 2 到 4 倍(但它也被设计为填充区域,正如 OP 在该问题中所问的那样,所以并不意外。)

    3. 下面的代码改进了Stanislav's rectangle method(每次从当前字体大小开始,而不是每次都恢复到MIN_FONT_SIZE),因此运行速度比该代码,尤其是当窗口/字体很大时。

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

    【讨论】:

      猜你喜欢
      • 2012-11-11
      • 2011-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-28
      • 2011-01-28
      • 1970-01-01
      相关资源
      最近更新 更多