BufferedImage中的drawString消失

时间:2014-10-14 02:34:58

标签: java swing

我希望你可以帮我解决我的drawString中的问题。

我在Factory类中做一些绘图并返回一个带有String的BufferedImage。

public class Factory {

   public BufferedImage create() {
       TempPanel tempPanel = new TempPanel(new Dimension(100, 100));
       return tempPanel.createImage();
   }

   private class TempPanel extends JPanel {

       public TempPanel(Dimension d) {
           this.setVisible(true);
           this.setSize(d);
       }

       public BufferedImage createImage() {
           BufferedImage bi = new BufferedImage(this.getSize().getWidth(), this.getSize().getHeight(), BufferedImage.TRANSLUCENT);
           this.paintComponent(bi.createGraphics());
           return bi;
       }

       @Override
       public void paintComponent(Graphics g) {
           super.paintComponents(g);
           // General setup
           Graphics2D g2 = (Graphics2D) g;
           g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

           // Transparent Background
           g2.setComposite(AlphaComposite.Clear);
           g2.fillRect(0, 0, graphicalObject.width, graphicalObject.height);
           g2.setComposite(AlphaComposite.Src);

           // Different settings for a certain graphical object
           g2.setFont(new Font("TimesRoman", Font.PLAIN, 12);

           // Actual drawing
           g2.drawString("Test", 0, 0);
       }
    }
}

然后我还有一个JPanel,其中应该绘制这个图像:

public class Label extends JPanel {
   // ...
   @Override
   public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        Factory factory = new Factory();
        BufferedImage img = factory.create();
        g2.drawImage(img, 0, 0, null);
   }
}

问题是文本仅在我最小化和恢复窗口时出现,但是一旦我开始在窗口内移动鼠标,文本就会再次消失。 当我调用drawRect()而不是drawString()时,一切正常吗?!

有人可以告诉我为什么吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

有很多事情很奇怪"我出去......

首先,您要创建一个新的Graphics上下文,但是您没有处置它。这可能会使资源保持开放状态,实际上可能会阻止在某些操作系统上呈现内容......

所以不是......

BufferedImage bi = new BufferedImage(this.getSize().getWidth(), this.getSize().getHeight(), BufferedImage.TRANSLUCENT);
this.paintComponent(bi.createGraphics());

你应该做更像......的事情。

BufferedImage bi = new BufferedImage(getWidth(), getHeight(), BufferedImage.TRANSLUCENT);
Graphics2D g2d = bi.createGraphics();
this.paintComponent(g2d);
g2d.dispose();

其次,文本的渲染方式与大多数其他元素的渲染方式不同,也就是说,它不会从x / y开始向下/向右渲染,在大多数情况下,它从x / y开始渲染,略微,向上/向右。实际坐标基于Font s FontMetrics getAscent值...

所以,而不是......

            g2.setFont(new Font("TimesRoman", Font.PLAIN, 12));
            // Actual drawing
            g2.drawString("Test", 0, 0);

你应该做更像......的事情。

            g2.setFont(new Font("TimesRoman", Font.PLAIN, 12));
            FontMetrics fm = g2.getFontMetrics();
            // Actual drawing
            g2.drawString("Test", 0, fm.getAscent());

请参阅Working with Text APIs或更多详细信息......

第三,JComponent并且通过扩展,从它延伸的任何东西都是ImageObsever,这很重要,因为并非所有绘制的东西都可以立即显示,有时需要进一步处理,而不是自己处理这种烦恼,你可以委派责任,而不是......

g2.drawImage(img, 0, 0, null);

你应该做更像......的事情。

g2.drawImage(img, 0, 0, this);

这允许组件侦听底层图像并响应可能发生在图像数据上的任何更改并自行更新。

... Forthly

private class TempPanel extends JPanel {

   public TempPanel(Dimension d) {
       this.setVisible(true);
       this.setSize(d);
   }

   public BufferedImage createImage() {
       BufferedImage bi = new BufferedImage(this.getSize().getWidth(), this.getSize().getHeight(), BufferedImage.TRANSLUCENT);
       this.paintComponent(bi.createGraphics());
       return bi;
   }

   @Override
   public void paintComponent(Graphics g) {
       super.paintComponents(g);
       // General setup
       Graphics2D g2 = (Graphics2D) g;
       g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

       // Transparent Background
       g2.setComposite(AlphaComposite.Clear);
       g2.fillRect(0, 0, graphicalObject.width, graphicalObject.height);
       g2.setComposite(AlphaComposite.Src);

       // Different settings for a certain graphical object
       g2.setFont(new Font("TimesRoman", Font.PLAIN, 12);

       // Actual drawing
       g2.drawString("Test", 0, 0);
   }
}

吓坏了我... Swing组件意味着附加到它们被渲染的本地对等体上,它们也被优化为在它们不可显示时不绘画,这可能会导致渲染失效...

事实上,你可以使用像...这样的东西来实现同样的目标。

public static class Factory {

    private static Renderer renderer;

    public BufferedImage create() {

        if (renderer == null) {
            renderer = new Renderer(new Dimension(100, 100));
        }

        return renderer.createImage();
    }

    private class Renderer {

        private Dimension size;

        public Renderer(Dimension size) {
            this.size = size;
        }

        public BufferedImage createImage() {
            BufferedImage bi = new BufferedImage(size.width, size.height, BufferedImage.TRANSLUCENT);
            Graphics2D g2 = bi.createGraphics();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            // Transparent Background
            g2.setComposite(AlphaComposite.Clear);
            g2.fillRect(0, 0, graphicalObject.width, graphicalObject.height);
            g2.setComposite(AlphaComposite.Src);
            // Different settings for a certain graphical object
            g2.setFont(new Font("TimesRoman", Font.PLAIN, 12));
            FontMetrics fm = g2.getFontMetrics();

            // Actual drawing
            g2.drawString("Test", 0, fm.getAscent());
            g2.dispose();
            return bi;
        }

    }
}

哪个会将实际绘画与其他任何东西分开,并让你控制它......