2011-02-06 12 views
10

Sto provando a scrivere un'applicazione che ha bisogno di disegnare molte stringhe usando la classe Graphics2D in Java. Ho bisogno di ottenere le dimensioni di ogni oggetto String (per calcolare la posizione esatta di ogni stringa). Ci sono così tante stringhe che dovrebbe essere fatto prima che il metodo paint() venga chiamato e solo una volta all'inizio del mio programma (quindi non ho ancora l'oggetto Graphics2D). So che esiste un metodo Font.getStringBounds() ma ha bisogno di un oggetto FontRenderContext come parametro.Ottenere la dimensione della stringa in java (senza avere un oggetto Graphics disponibile)

quando ho cercato di creare il mio oggetto:

FontRenderContext frc = new FontRenderContext(MyFont.getTransform(), true, true) 

e quindi ottenere le stringhe limiti che ho sempre ottenere dimensioni diverse rispetto a quando ottengo FontRenderContext utilizzando il metodo Graphics2D.getFontRenderContext() metodo all'interno paint() . Le differenze non sono grandi (circa 1E-3), ma mi chiedo perché c'è qualche differenza?

Tuttavia, esiste un modo migliore e sicuro per ottenere le dimensioni di una stringa?

Thnx per qualsiasi aiuto in anticipo!

risposta

6

Provare con la classe FontMetrics; il metodo stringWidth restituisce la dimensione di una stringa. Un esempio:

JComponent c = getSomeKindOfJComponent(); 
FontMetrics fm = c.getFontMetrics(c.getFont()); // or another font 
int strw = fm.stringWidth("My text"); 
+3

stringWidth non restituisce la dimensione della stringa valida perché non considera l'anti-aliasing e altre funzionalità (come la spaziatura tra i caratteri). –

0

Ecco un frammento di codice che fa qualcosa di simile - ha scritto per abbreviare la stringa ad un determinato numero di pixel.

public static String abbreviate(final Graphics2D g2, final String text, final int fitToWidth) { 
    // define how many characters in the caption can be drawn 
    final FontMetrics fm = g2.getFontMetrics(); 
    Rectangle2D textBounds = fm.getStringBounds(text, g2); 
    int count = text.length(); 
    while ((textBounds.getWidth() > fitToWidth) && (count > 4)) { 
     textBounds = fm.getStringBounds(text.substring(0, count--), g2); 
    } 
    return count == text.length() ? text : StringUtils.abbreviate(text, count); 
} 
+0

Questo non è ciò di cui ho bisogno: voglio ottenere limiti di stringa esatti senza oggetto Graphics2D. –

+1

@ coder89 Bene. Le proprietà dell'istanza Graphics2D potrebbero essere diverse durante il ciclo di vita dell'applicazione. Come hai indicato abbastanza correttamente, è necessario prendere in considerazione "anti-aliasing e altre funzionalità", che non è possibile senza un'istanza specifica di Graphics2D. – 01es

0

Oltre a utilizzare FontMetrics, un JLabel può essere utilizzato per determinare la dimensione di entrambi (base HTML) testo reso non formattato e. Ecco un esempio.

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.GradientPaint; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 

import java.awt.image.BufferedImage; 

import javax.swing.JOptionPane; 
import javax.swing.JLabel; 
import javax.swing.ImageIcon; 

/** Sample code obtained from a thread on the Oracle forums that I cannot 
locate at this instant. My question was related to an unexpected rendering of 
JLabel. It was resolved by the 'added this' line courtesy of Darryl Burke. */ 
public class LabelRenderTest { 

    String title = "<html><body style='width: 160px; padding: 8px'>" 
      + "<h1>Do U C Me?</h1>" 
      + "Here is a long string that will wrap. " 
      + "The effect we want is a multi-line label."; 

    LabelRenderTest() { 
    BufferedImage image = new BufferedImage(
      640, 
      480, 
      BufferedImage.TYPE_INT_RGB); 
    Graphics2D imageGraphics = image.createGraphics(); 
    GradientPaint gp = new GradientPaint(
      20f, 20f, Color.blue, 
      620f, 460f, Color.white); 
    imageGraphics.setPaint(gp); 
    imageGraphics.fillRect(0, 0, 800, 600); 

    JLabel textLabel = new JLabel(title); 
    textLabel.setSize(textLabel.getPreferredSize()); // <==== added this 

    Dimension d = textLabel.getPreferredSize(); 
    BufferedImage bi = new BufferedImage(
      d.width, 
      d.height, 
      BufferedImage.TYPE_INT_ARGB); 
    Graphics g = bi.createGraphics(); 
    g.setColor(new Color(255, 255, 255, 128)); 
    g.fillRoundRect(
      0, 
      0, 
      bi.getWidth(null), 
      bi.getHeight(null), 
      15, 
      10); 
    g.setColor(Color.black); 
    textLabel.paint(g); 
    Graphics g2 = image.getGraphics(); 
    g2.drawImage(bi, 20, 20, null); 

    ImageIcon ii = new ImageIcon(image); 
    JLabel imageLabel = new JLabel(ii); 

    JOptionPane.showMessageDialog(null, imageLabel); 
    } 

    public static void main(String[] args) { 
    LabelRenderTest ist = new LabelRenderTest(); 
    } 
} 

Edit 1: Per quanto riguarda il tuo commento "molte corde". Dipingi le stringhe su una BufferedImage che viene rigenerata solo se necessario. Usa il BufferedImage ogni volta che viene chiamato paintComponent().

2

Si potrebbe anche voler controllare SwingUtilities.computeStringWidth.

+0

restituisce la larghezza come numero intero - Ho bisogno di qualcosa di più preciso –

0

per amor storica, ecco come penso lo ha fatto in origine (JRuby java pseucodoe)

font = UIManager.getFont("Label.font") 
frc = java.awt.font.FontRenderContext.new(font.transform, true, true) 
textLayout = java.awt.font.TextLayout.new(text, font, frc) 
textLayout.bounds.width 
2

Nev-ah. Gon-na. Accadere.

Il motivo è il rendering e il calcolo che stai cercando da FRC è specifico per un contesto grafico, ad esempio un oggetto Graphics2D specifico. Quello a cui sei interessato è quello che ti viene consegnato in fase di runtime - è come nessun altro (devi supporre).

È possibile calcolare quanto si vuole utilizzare un FRC da qualche altro Graphics2D, ma i tuoi calcoli tutti tutti per nulla quando si tenta di utilizzarli in fase di esecuzione con l'Graphics2D paintComponent viene consegnato, che è la Craphics2D si' che userò, non importa quale.

Quindi, sì, sarebbe bello ma è del tutto teorico. Tutta quella bella informazione è effettivamente bloccata all'interno di questo FRC perché senza l'esatto Graphics2D, l'AttributedString è in realtà attratto da, che il FRC è peggio che inutile - è un'illusione che potresti provare ad abbracciare.

Ha senso, dal momento che tutto dipende in realtà da Graphics2D in cui vieni consegnato in fase di esecuzione. Quindi la cosa migliore da fare è accettarlo e scrivere il tuo codice per chiamare da paintComponent a qualsiasi oggetto e qualsiasi computazione specializzata che devi fare e costruire il tuo design attorno al fatto che QUESTO è come stanno le cose.

Sono una buona domanda e una buona cosa che vorrei poterti fare, semplicemente, non puoi. Vedi altre persone che lo chiedono altrove sul web, in altri forum. Notare la mancanza di risposte utili e/o silenzio assordante.