Frage

Ich verwende FontMetrics.getHeight() die Höhe des Strings zu bekommen, aber es gibt mir einen falschen Wert, die Unterlängen der Zeichenfolge Zeichen abgeschnitten wird. Gibt es eine bessere Funktion, die ich verwenden kann?

War es hilfreich?

Lösung

Die nachstehende getStringBounds() Methode basiert auf der GlyphVector für den aktuellen Graphics2D Schrift basiert, die für eine Zeile Text-String sehr gut funktioniert:

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

Beachten Sie, dass ich die Einfuhren aus Gründen der Übersichtlichkeit weggelassen haben.

Das Ergebnis:

Ergebnis-Screenshot.

Andere Tipps

Was macht Sie denken, es den falschen Wert zurückgibt? Es ist viel wahrscheinlicher, dass Ihre Erwartung dessen, was es gibt nicht die Spezifikation entspricht. Beachten Sie, dass es völlig in Ordnung, wenn einige Glyphen in der Schrift gehen über oder unter diesen Werten.

getMaxDescent() und getMaxAscent() sollten Ihnen die absoluten Maximalwert dieser Felder für jede Glyphe sagen, in der Schriftart.

Wenn Sie die Metriken für einen bestimmten String wissen wollen, dann möchten Sie auf jeden Fall getLineMetrics() nennen.

Ich schrieb vor kurzem den Code unten als ich brauchte pixelgenaue Höhenmessungen für bestimmte Bereiche der Schriftart (zum Beispiel: alle niedrigeren Zeichen oder alle Zahlen).

Wenn Sie schneller Code benötigen (Mine hat für Schleifen) Ich würde empfehlen, es einmal bei der Inbetriebnahme laufen alle Werte zu erhalten (zum Beispiel von 1 bis 100) in einem Array und dann das Array verwenden stattdessen.

Der Code im Grunde zieht alle Zeichen aus der Eingabezeichenfolge an der gleichen Stelle auf einer 250x250-Bitmap überlappt (Erhöhung oder Verringerung, wenn erforderlich), beginnt es für die Pixel von oben schaut, dann von unten, dann gibt sie die maximale Höhe gefunden. Es funktioniert mit normalen Strings, auch wenn es für Zeichenbereiche entwickelt wurde. Das heißt, es ist eine Art von Redundanz, wenn wiederholen reguläre Strings als einige der Charaktere zu bewerten. Also, wenn Ihr imput Zeichenfolge das Alphabet Zahl (26) übersteigt, die Verwendung als ‚TRANGE‘ imput: „abcd ... z“ und andere Zeichen, die verwendet werden können. Es ist schneller.

Ich hoffe, das hilft.

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

getHeight() kann nicht die Unterlängen eines Strings abgeschnitten, nur die Zeichenfolge Zeichnung kann das tun. Sie verwenden die Höhe von getHeight zurück irgendwie die Zeichenfolge zu ziehen, und wahrscheinlich missbräuchlich Sie die Höhe. Zum Beispiel, wenn Sie den Startpunkt der Schnur am Boden eines Kastens positionieren getHeight () hoch ist, dann ist die Basislinie des Textes wird am unteren Rand der Box sitzen, und sehr wahrscheinlich werden die Unterlängen abgeschnitten.

Text Geometrie ist ein komplexes Thema, infundiert mit bizarren historischen Artefakten. Wie andere vorgeschlagen haben, verwenden Sie getAscent und getDescent zu versuchen, die Grundlinie zu positionieren, richtig in Ihrem System.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top