在JTextField中保留文本的同时最大化字体大小

时间:2013-10-15 21:53:46

标签: java swing fonts jtextfield font-size

我有一个JTextField,根据分辨率可能会有所不同。 JTextField将包含一个3个字母的字符串。

我想设置JTextField的字体大小,以最大化字体大小,同时仍然完美地在JTextField中使用文本FIT。

有算法吗?

3 个答案:

答案 0 :(得分:2)

鉴于fontsize a中字符串的宽度为x。可用空间为s。然后你可以使用因子s / x来扩展你的字体。因此,选择a * s / x作为fontsize。要了解x,请使用任意fontsize a计算字符串的宽度。

答案 1 :(得分:0)

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

String length in pixels in Java

Java: Getting a font with a specific height in pixels

...为了对我的问题写一个完整的答案。在这里。感谢所有贡献者。

您需要导入以下内容:

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

答案 2 :(得分:0)

是的,我知道这是一个古老的线程......但我只是遇到了类似的问题并创建了自定义 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));
            }               
        }
    }
}