Getting string size in java (without having a Graphics object available)

前端 未结 6 582
南方客
南方客 2021-01-11 12:37

I\'m trying to write application which need to draw many strings using Graphics2D class in Java. I need to get sizes of each String object (to calculate exact p

相关标签:
6条回答
  • 2021-01-11 13:22

    for historical sake,here's how I think he did it originally (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
    
    0 讨论(0)
  • 2021-01-11 13:26

    Here is a snippet of code that does something similar -- wrote it for abbreviating the string to a given number of pixels.

    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 讨论(0)
  • 2021-01-11 13:27

    Try with the FontMetrics class; the stringWidth method returns the size of a string. An example:

    JComponent c = getSomeKindOfJComponent();
    FontMetrics fm = c.getFontMetrics(c.getFont()); // or another font
    int strw = fm.stringWidth("My text");
    
    0 讨论(0)
  • 2021-01-11 13:30

    You might also want to check out SwingUtilities.computeStringWidth.

    0 讨论(0)
  • 2021-01-11 13:30

    Besides using FontMetrics, a JLabel can be used to determine the size of both unformatted and (basic HTML) rendered text. Here is an example.

    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: As to your "many strings" comment. Paint the strings to a BufferedImage that is only regenerated if needed. Use the buffered image each time paintComponent() is called.

    0 讨论(0)
  • 2021-01-11 13:39

    Nev-ah. Gon-na. Happen.

    The reason is the rendering and computation you're looking for from FRC is specific to a Graphics context, i.e. a specific Graphics2D object. The one you're interested in is one you're handed at runtime- it's like no other (you have to assume).

    You can compute as much as you want using an FRC from some other Graphics2D, but your computations all all for naught when you try to use them at runtime with the Graphics2D paintComponent is handed, which is the Graphics2D you're going to use, no matter what.

    So, yes, this would be nice but it's entirely theoretical. All that nice information is effectively locked away inside that FRC because without the exact Graphics2D the AttributedString is actually going to be drawn to, that FRC is worse than useless- it's an illusion you might actually try to embrace.

    It makes sense, since everything really IS dependent on the Graphics2D you get handed at runtime. So the best thing to do is just accept it and write your code to call out from within paintComponent out to whatever objects and whatever specialized computation you have to do and build your design around the fact that THIS is the way things are.

    I's a good question and a good thing to wish you could do, just, you can't. You see other people asking for this elsewhere on the web, in other forums. Notice the lack of useful answers and / or deafening silence.

    0 讨论(0)
提交回复
热议问题