9 Replies Latest reply: Jan 12, 2010 3:44 PM by 793415 RSS

    Render JLabel without 1st displaying

    793415
      Task: Put HTML rendered text onto an image.

      I want to put HTML rendered text onto images (captions, titles etc.). The HTML is simple and a JLabel will suffice to render it. The problem I am seeing is that the JLabel must be made visible prior to rendering, otherwise the content of the JLabel is blank.

      This seems odd, since the JRE is able to determine the bounds of the rendered text in the JLabel, even if it was never displayed. I could imagine situations where, until it is rendered, the exact layout and size is indeterminate - but in this case, the JRE is able to determine the size it will eventually have when on-screen.

      Is there a way around 1st displaying the JLabel, prior to rendering it?

      In this example, if you choose Yes to the "Pre render label", the text will appear. Otherwise the content will be blank.
      import java.awt.*;
      import java.awt.image.*;
      import javax.swing.*;
      
      public class LabelRenderTest {
      
          JFrame f;
          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() {
              f = new JFrame("Label Render Test");
              f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      
              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);
              int result = JOptionPane.showConfirmDialog(
                  f, "Pre render label?");
              if (result==JOptionPane.OK_OPTION) {
                  JOptionPane.showMessageDialog(f, textLabel);
              }
      
              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,64) );
              g.fillRoundRect( 
                  0, 
                  0, 
                  bi.getWidth(f), 
                  bi.getHeight(null), 
                  15, 
                  10 );
              g.setColor(Color.black);
              textLabel.paint( g );
              Graphics g2 = image.getGraphics();
              g2.drawImage(bi, 20, 20, f);
      
              ImageIcon ii = new ImageIcon(image);
              JLabel imageLabel = new JLabel(ii);
      
              f.getContentPane().add( imageLabel );
              f.pack();
          }
      
          public void setVisible(boolean visibility) {
              f.setVisible(visibility);
          }
      
          public static void main(String[] args) {
              LabelRenderTest ist = new LabelRenderTest();
              ist.setVisible(true);
          }
      }
      ( I offer no apologies for the text-speak in the level 1 header. We're trying to achieve something here, damn it! ;)
        • 1. Re: Render JLabel without 1st displaying
          843807
          It seems that the JLabel must be made "displayable," e.g. rendered on-screen or put into a pack()'d container such as JFrame. The following is sufficient:
          label = ...;
          JFrame frame = new JFrame();
          frame.getContentPane().add(label);
          frame.pack();
          // Now do nothing with frame, but label can now be rendered as you are doing.
          • 2. Re: Render JLabel without 1st displaying
            Darryl Burke
            Added one line:
            import java.awt.*;
            import java.awt.image.BufferedImage;
            import javax.swing.*;
            
            public class LabelRenderTest {
            
              JFrame f;
              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() {
                f = new JFrame("Label Render Test");
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
                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
                int result = JOptionPane.showConfirmDialog(
                        f, "Pre render label?");
                if (result == JOptionPane.OK_OPTION) {
                  JOptionPane.showMessageDialog(f, textLabel);
                }
            
                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, 64));
                g.fillRoundRect(
                        0,
                        0,
                        bi.getWidth(f),
                        bi.getHeight(null),
                        15,
                        10);
                g.setColor(Color.black);
                textLabel.paint(g);
                Graphics g2 = image.getGraphics();
                g2.drawImage(bi, 20, 20, f);
            
                ImageIcon ii = new ImageIcon(image);
                JLabel imageLabel = new JLabel(ii);
            
                f.getContentPane().add(imageLabel);
                f.pack();
              }
            
              public void setVisible(boolean visibility) {
                f.setVisible(visibility);
              }
            
              public static void main(String[] args) {
                LabelRenderTest ist = new LabelRenderTest();
                ist.setVisible(true);
              }
            }
            db
            • 3. Re: Render JLabel without 1st displaying
              793415
              BoBear2681 wrote:
              It seems that the JLabel must be made "displayable," e.g. rendered on-screen or put into a pack()'d container such as JFrame. The following is sufficient:
              label = ...;
              JFrame frame = new JFrame();
              frame.getContentPane().add(label);
              frame.pack();
              // Now do nothing with frame, but label can now be rendered as you are doing.
              You bloody beauty! It works now, just as I wanted. Thanks.
              • 4. Re: Render JLabel without 1st displaying
                Darryl Burke
                It seems that the JLabel must be made "displayable," e.g. rendered on-screen or put into a pack()'d container such as JFrame. The following is sufficient:
                Actually, as my one-line addition shows, it's sufficient for the size to be set. That is achieved indirectly by packing a container, which causes its contents to be layed out.

                db
                • 5. Re: Render JLabel without 1st displaying
                  843807
                  You only need to set the size of the label per DarrylBurke example.
                  • 6. Re: Render JLabel without 1st displaying
                    793415
                    DarrylBurke wrote:
                    Added one line:
                    Now that is what I call 'economical'. :-)
                    ..
                    textLabel.setSize(textLabel.getPreferredSize()); // <==== added this
                    ..
                    Brilliant! I'd apologise for not having held back some of the Dukes to award to you, if I didn't think you'd heap scorn on me for doing so.

                    Edit 1:
                    I'll go with setting the size, since it saves creating an otherwise useless frame.

                    Edited by: AndrewThompson64 on Jan 13, 2010 8:43 AM
                    • 7. Re: Render JLabel without 1st displaying
                      843807
                      I only assumed that being displayable was a requirement after that thread a few days ago about that same topic. So I tried it out and it seemed to be the cause. Guess the real cause was just an uninitialized size. Sorry bout that!
                      • 8. Re: Render JLabel without 1st displaying
                        793415
                        BoBear2681 wrote:
                        ..Sorry bout that!
                        (dismissive) Peh! You read my post, ran the code, came up with a solution, and posted it promptly. No reason for apologies.

                        And as an aside: forums rock. I must have wasted 10 hours trying to get that to work as I wanted.
                        • 9. Re: Render JLabel without 1st displaying
                          793415
                          BoBear2681 wrote:
                          I only assumed that being displayable was a requirement after that thread a few days ago about that same topic. ...
                          It was ultimately about making titles for groups of screenshots in an animation.

                          In the process of making the program that adds titles to groups of screenshots, I realised most of the coding was to do with editing the details of the titles themselves. As a result I wrote [ImaT - Image Titler|http://pscode.org/imat/] first, just to get the the editor (mostly) working.