2008-12-15 46 views

回答

19

getStringBounds()方法是基於GlyphVector當前Graphics2D字體,它非常適用於文本的一個線串:

public class StringBoundsPanel extends JPanel 
{ 
    public StringBoundsPanel() 
    { 
     setBackground(Color.white); 
     setPreferredSize(new Dimension(400, 247)); 
    } 

    @Override 
    protected void paintComponent(Graphics g) 
    { 
     super.paintComponent(g); 

     Graphics2D g2 = (Graphics2D) g; 

     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 
          RenderingHints.VALUE_ANTIALIAS_ON); 

     // must be called before getStringBounds() 
     g2.setFont(getDesiredFont()); 

     String str = "My Text"; 
     float x = 140, y = 128; 

     Rectangle bounds = getStringBounds(g2, str, x, y); 

     g2.setColor(Color.red); 
     g2.drawString(str, x, y); 

     g2.setColor(Color.blue); 
     g2.draw(bounds); 

     g2.dispose(); 
    } 

    private Rectangle getStringBounds(Graphics2D g2, String str, 
             float x, float y) 
    { 
     FontRenderContext frc = g2.getFontRenderContext(); 
     GlyphVector gv = g2.getFont().createGlyphVector(frc, str); 
     return gv.getPixelBounds(null, x, y); 
    } 

    private Font getDesiredFont() 
    { 
     return new Font(Font.SANS_SERIF, Font.BOLD, 28); 
    } 

    private void startUI() 
    { 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.add(this); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) throws Exception 
    { 
     final StringBoundsPanel tb = new StringBoundsPanel(); 

     SwingUtilities.invokeAndWait(new Runnable() 
     { 
      public void run() 
      { 
       tb.startUI(); 
      } 
     }); 
    } 
} 

請注意,我省略了清晰的進口。

其結果是:

Result screenshot.

+1

@nierito偉大的答案和偉大的演示呢!根據你所說的,我已經盡力縮短你的代碼(假設一個定義了`Font`,並從中得到了`FontMetrics`)。它的工作原理相當不錯。 `字體。createGlyphVector(fontMetrics.getFontRenderContext(),text).getVisualBounds()。getHeight();` – 2013-01-30 23:13:34

11

是什麼讓你覺得它返回錯誤的值?你很可能期望它返回的內容與規範不符。請注意,如果字體中的某些字形超出或低於這些值,那就很好了。

getMaxDescent()getMaxAscent()應該告訴你字體中任何字形的那些字段的絕對最大值。

如果您想知道特定字符串的指標,那麼您一定要致電getLineMetrics()

2

getHeight()不能切斷字符串的下行,只能繪製字符串可以做到這一點。您正在使用從getHeight返回的高度以某種方式繪製字符串,並且可能是濫用了高度。例如,如果你在一個盒子,是的getHeight的底部位置字符串的起點()高,那麼你的文本的基線將坐在箱子的底部邊緣,並且極有可能緣將被裁剪。

文字幾何是一個複雜的話題,注入奇異的歷史文物。正如其他人所建議的那樣,請使用getAscentgetDescent嘗試在您的框中正確定位基線。

3

我最近寫下面的代碼作爲我所需字體的特定範圍的像素完美高度測量值(例如:所有較低的字符,或所有的數字)。

如果需要更快的代碼(我擁有for循環)我會建議在啓動時運行一次它獲得的所有值(例如,從1到100)在一個數組,然後使用數組來代替。

該代碼基本上將輸入字符串中的所有字符繪製在250x250位圖上重疊的相同位置(如果需要增加或減少),它將從頂部開始尋找像素,然後從底部開始,然後返回找到的最大高度。它適用於普通字符串,即使它是爲字符範圍而設計的。這意味着在評估常規字符串時會有一些冗餘,因爲某些字符會重複。因此,如果您的輸入字符串超過字母數(26),請使用'tRange'輸入:「abcd ... z」和其他可能使用的字符。它更快。

希望有所幫助。

public int getFontPixelHeight(float inSize, Paint sourcePaint, String tRange) 
{ 
    // It is assumed that the font is already set in the sourcePaint 

    int bW = 250, bH = 250;          // bitmap's width and height 
    int firstContact = -1, lastContact = -2;     // Used when scanning the pixel rows. Initial values are set so that if no pixels found, the returned result is zero. 
    int tX = (int)(bW - inSize)/2, tY = (int)(bH - inSize)/2; // Used for a rough centering of the displayed characters 

    int tSum = 0; 

    // Preserve the original paint attributes 
    float oldSize = sourcePaint.getTextSize(); 
    int oldColor = sourcePaint.getColor(); 
    // Set the size/color 
    sourcePaint.setTextSize(inSize); sourcePaint.setColor(Color.WHITE); 

    // Create the temporary bitmap/canvas 
    Bitmap.Config bConf = Bitmap.Config.ARGB_8888; 
    Bitmap hld = Bitmap.createBitmap(250, 250, bConf); 
    Canvas canv = new Canvas(hld); 

    for (int i = 0; i < bH; i++) 
    { 
     for (int j = 0; j < bW; j++) 
     { 
      hld.setPixel(j, i, 0); // Zero all pixel values. This might seem redundant, but I am not quite sure that creating a blank bitmap means the pixel color value is indeed zero, and I need them to be zero so the addition performed below is correct. 
     } 
    } 

    // Display all characters overlapping at the same position 
    for (int i = 0; i < tRange.length(); i++) 
    { 
     canv.drawText("" + tRange.charAt(i), tX, tY, sourcePaint); 
    } 

    for (int i = 0; i < bH; i++) 
    { 
     for (int j = 0; j < bW; j++) 
     { 
      tSum = tSum + hld.getPixel(j, i); 
     } 

     if (tSum > 0) // If we found at least a pixel, save row index and exit loop 
     { 
      firstContact = i; 
      tSum = 0; // Reset 
      break; 
     } 
    } 

    for (int i = bH - 1; i > 0 ; i--) 
    { 
     for (int j = 0; j < bW; j++) 
     { 
      tSum = tSum + hld.getPixel(j, i); 
     } 

     if (tSum > 0) // If we found at least a pixel, save row index and exit loop 
     { 
      lastContact = i; 
      break; 
     } 
    } 

    // Restore the initial attributes, just in case the paint was passed byRef somehow 
    sourcePaint.setTextSize(oldSize); 
    sourcePaint.setColor(oldColor); 

    return lastContact - firstContact + 1; 
} 
相關問題