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

Java 如何根据容器大小平滑地自动调整多个JLabel的字体大小?,java,swing,fonts,resize,jlabel,Java,Swing,Fonts,Resize,Jlabel,我需要根据用于调整容器大小的比例因子调整多个JLabel的字体大小。为此,我将每个JLabel的字体设置为null,以便它们采用容器的字体。它是有效的,但也会产生奇怪的结果 具体来说,文本似乎“滞后”于容器,有时甚至被截断。我想避免这种行为。知道怎么做吗 模拟行为的示例代码: import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Dimension; impo

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

}
导入java.awt.BorderLayout;
导入java.awt.Color;
导入java.awt.Container;
导入java.awt.Dimension;
导入java.awt.Font;
导入java.awt.GridBagConstraints;
导入java.awt.GridBagLayout;
导入java.awt.Insets;
导入java.awt.geom.AffineTransform;
导入javax.swing.BorderFactory;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
导入javax.swing.JSlider;
导入javax.swing.SwingUtilities;
导入javax.swing.WindowConstants;
导入javax.swing.event.ChangeEvent;
导入javax.swing.event.ChangeListener;
公共类TextResize实现可运行{
公共静态void main(字符串[]args){
TextResize示例=新建TextResize();
调用器(示例);
}
公开募捐{
JFrame frame=新JFrame(“JLabel文本调整”);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setPreferredSize(新尺寸(800400));
Container=frame.getContentPane();
container.setLayout(新的BorderLayout());
final JPanel labelContainer=新JPanel(新GridBagLayout());
labelContainer.setboorder(BorderFactory.createLineBorder(Color.black));
//初始字体
final Font textFont=新字体(“Lucida控制台”,Font.PLAIN,10).deriveFont(仿射Transform.getScaleInstance(1,1));
labelContainer.setFont(textFont);
GridBagConstraints c=新的GridBagConstraints();
c、 fill=GridBagConstraints.BOTH;
c、 插图=新插图(0,10,0,10);
c、 权重x=1;
对于(int i=0;i<5;i++){
JLabel f=新的JLabel(“这里的文本可能有很多单词”);
f、 setboorder(BorderFactory.createLineBorder(Color.green));
f、 setFont(null);//从父级获取字体
c、 gridy=i;
添加(f,c);
}
JSlider滑块=新JSlider(0500010000);
slider.addChangeListener(新的ChangeListener(){
double containerWidth=labelContainer.getPreferredSize().getWidth();
double containerHeight=labelContainer.getPreferredSize().getHeight();
@凌驾
公共无效状态已更改(ChangeEvent ev){
JSlider source=(JSlider)ev.getSource();
双刻度=(双)(source.getValue()/10000d);
//缩放容器
labelContainer.setSize((int)(containerWidth*刻度),(int)(containerHeight*刻度));
//调整字体:为什么会“滞后”?为什么有时会截断?
Font newFont=textFont.deriveFont(仿射转换.getScaleInstance(缩放,缩放));
labelContainer.setFont(newFont);
//打印(font.getSize()是否不变?)
System.out.println(scale+“”+newFont.getTransform()+newFont.getSize2D());
}
});
添加(滑块,BorderLayout.NORTH);
JPanel测试=新的JPanel();
test.setLayout(null);
labelContainer.setBounds(5,5,labelContainer.getPreferredSize().width,labelContainer.getPreferredSize().height);
测试。添加(labelContainer);
container.add(test,BorderLayout.CENTER);
frame.pack();
frame.setVisible(true);
}
}
图片:

谢谢


-s

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


我在某种程度上解决了添加以下内容的问题:

@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种方法的以下信息非常有用

  • 如果在多调用的基础上使用,则会有一些限制(例如在sizeChanged侦听器或LayoutManager中)

  • 比Stanislav的速度慢2到4倍(但它的设计也是为了按照OP在该问题中提出的要求填充两个方向的区域,所以这并不意外。)

  • 下面的代码改进了(每次从当前的字体大小开始,而不是每次恢复到最小字体大小),因此运行速度比代码快20到50倍,尤其是当窗口/字体较大时

  • 它还解决了该代码中的一个限制,该限制仅对位于0,0的标签有效(如此处给出的示例所示)。下面的代码适用于面板上和任意位置的多个标签

    import javax.swing.*;
    导入java.awt.*;
    导入java.awt.event.ComponentAdapter;
    导入java.awt.event.ComponentEvent;
    //改进版http://java-sl.com/tip_adapt_label_font_size.html
    公共类FontResizingLabel扩展了JLabel{
    公共静态最终整数最小字体大小=3;
    公共静态最终整数最大字体大小=240;
    图形g;
    int currFontSize=0;
    公共FontResizingLabel(字符串文本){
    超级(文本);
    currFontSize=this.getFont().getSize();
    init();
    }
    受保护的void init(){
    addComponentListener(新的ComponentAdapter(){
    公共无效组件已恢复(组件事件e){
    AdapteLabelfont(FontResizingLabel.this);
    }
    });
    }
    受保护的无效适配器(JLabel){
    如果(g==null){
    返回;
    }
    currFontSize=this.getFont().getSize();
    矩形r=l.getBounds();
    r、 x=0;
    r、 y