0

我有一个 JTextField,它的大小可能会因分辨率而异。JTextField 将包含一个 3 个字母的字符串。

我想以这样一种方式设置 JTextField 的字体大小,以最大化字体大小,同时仍然完美地使文本适合 JTextField 内部。

有没有算法可以做到这一点?

4

3 回答 3

2

给定字体大小中字符串的宽度ax. 可用空间为s。然后你显然可以使用 factor: 来放大你的字体s / x。所以选择a * s / x字体大小。要知道x,用任意字体大小计算字符串的宽度a

于 2013-10-15T21:56:37.467 回答
1

是的,我知道这是一个古老的线程......但我只是遇到了类似的问题并创建了自定义 JTextField 类来解决它。此类使用一些“校准文本”,这是我的实现所独有的,但对于其他用途很容易更改。

因此,它将在两种情况下更改字体:

  • 控件已调整大小 - 使用静态“校准文本”来确定大小
  • 文本更改 - 根据当前文本动态调整文本大小(向上和向下)
public class DynamicText extends JTextField implements ComponentListener
{
    private final int MIN_SIZE = 5;
    private final int MAX_SIZE = 100;

    private int pfvMinFontSize = 5;        // minimum font size
    private int pfvMaxFontSize = 100;        // maximum font size
    private boolean pfvAutoScale = true;    // enabled the autoscaling feature
    
    int cached_width = 0;
    int cached_height = 0;
    
    int widthLimitPixels;
    float calcMax;
                
    public DynamicText()
    {
        super();
        this.getDocument().addDocumentListener(new TextChanged(this));
        addComponentListener(this);
    }

    public DynamicText(int cols)
    {
        super(cols);
        this.getDocument().addDocumentListener(new TextChanged(this));
        addComponentListener(this);
    }

    public int getMinFontSize()
    {
        return pfvMinFontSize;
    }

    public void setMinFontSize(int val)
    {
        if (val >= MIN_SIZE)
        {
            pfvMinFontSize = val;
        }
    }

    public int getMaxFontSize()
    {
        return pfvMaxFontSize;
    }

    // TODO: Check to make sure max is larger than min
    public void setMaxFontSize(int val)
    {
        if (val <= MAX_SIZE)
        {
            pfvMaxFontSize = val;
        }
    }

    public boolean getAutoScale()
    {
        return pfvAutoScale;
    }

    public void setAutoScale(boolean val)
    {
        pfvAutoScale = val;
    }

    @Override
    public void componentResized(ComponentEvent e)
    {
        // to keep from having to process multiple events
        if (this.getWidth() != cached_width || this.getHeight() != cached_height) 
        {
            cached_width = this.getWidth();
            cached_height = this.getHeight();
            
            /*
             * I do not consider this part of the optional AutoScale feature
             * since this will just scale the font for the "calibrated"
             * text this the maximum size
             */
            Font ft = this.getFont();
            float fontSize = pfvMinFontSize;
            FontMetrics metrics;
            int widthPixels = 0;

            int widthLimitPixels = this.getWidth() - this.getMargin().left - this.getMargin().right;
            float calcMax = (this.getHeight() - this.getMargin().top - this.getMargin().bottom) / 1.5f;

            while (widthPixels < widthLimitPixels && fontSize <= pfvMaxFontSize && fontSize <= calcMax)
            {
                ++fontSize;
                Font temp = ft.deriveFont(fontSize);
                metrics = this.getFontMetrics(temp);
                widthPixels = metrics.stringWidth("00000000 00000000 00000000 00000000 .b.");
            }
            --fontSize;
            this.setFont(ft.deriveFont(fontSize));
        }
    }

    @Override
    public void componentMoved(ComponentEvent e)
    {
        // nothing
    }

    @Override
    public void componentShown(ComponentEvent e)
    {
        // nothing
    }

    @Override
    public void componentHidden(ComponentEvent e)
    {
        // nothing
    }
    
    private class TextChanged implements DocumentListener
    {
        JTextField jtf;
        public TextChanged(JTextField source)
        {
            jtf = source;
        }
        
        @Override
        public void insertUpdate(DocumentEvent e)
        {
            resizeFont();
        }

        @Override
        public void removeUpdate(DocumentEvent e)
        {
            resizeFont();
        }

        @Override
        public void changedUpdate(DocumentEvent e)
        {
            // not applicable here...
        }
        
        private void resizeFont()
        {
            if (pfvAutoScale && jtf.getHeight() > 0)
            {
                Font ft = jtf.getFont();
                String viewText = jtf.getText();
                float fontSize = pfvMinFontSize;
                FontMetrics metrics;
                int widthPixels = 0;

                int widthLimitPixels = jtf.getWidth() - jtf.getMargin().left - jtf.getMargin().right;
                float calcMax = (jtf.getHeight() - jtf.getMargin().top - jtf.getMargin().bottom) / 1.5f;

                while (widthPixels < widthLimitPixels && fontSize <= pfvMaxFontSize && fontSize <= calcMax)
                {
                    ++fontSize;
                    Font temp = ft.deriveFont(fontSize);
                    metrics = jtf.getFontMetrics(temp);
                    widthPixels = metrics.stringWidth(viewText);
                }
                --fontSize;
                jtf.setFont(ft.deriveFont(fontSize));
            }               
        }
    }
}
于 2021-06-02T02:16:04.540 回答
0

我使用了 Martijn 的答案以及以下答案:

Java中的字符串长度(以像素为单位)

Java:获取具有特定高度(以像素为单位)的字体

...为了写下我的问题的完整答案。就这样吧。感谢所有做出贡献的人。

您将需要导入以下内容:

import javax.swing.JTextField;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.awt.FontMetrics;
import java.lang.Math;

...................................

public int getFontSize(JTextField text, int columnsToHold){
            //Create a sample test String (we will it later in our calculations)
            String testString = "";
            for(int i = 0; i<columnsToHold; i++){
                  testString = testString + "5";
            }


             //size will hold the optimal Vertical point size for the font
      Boolean up = null;
      int size = text.getHeight();  
      Font font;
     while (true) {
        font = new Font("Default", 0, size);
        int testHeight = getFontMetrics(font).getHeight();
        if (testHeight < height && up != Boolean.FALSE) {
            size++;
            up = Boolean.TRUE;
        } else if (testHeight > height && up != Boolean.TRUE) {
            size--;
            up = Boolean.FALSE;
        } else {
           break;
        }
    }
        //At this point, size holds the optimal Vertical font size

        //Now we will calculate the width of the sample string
    BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
    FontMetrics fm = img.getGraphics().getFontMetrics(font);
    int width = fm.stringWidth(testString);

        //Using Martijn's answer, we calculate the optimal Horizontal font size
    int newFontSize = size * textos[0].getWidth()/width;

        //The perfect font size will be the minimum between both optimal font sizes.
        //I have subtracted 2 from each font so that it is not too tight to the edges
    return Math.min(newFontSize-2, size-2);
}
于 2013-11-13T04:01:38.947 回答