为什么我的绘制方法只在某些时候起作用?

时间:2015-04-28 14:10:04

标签: java swing graphics

我知道,你可以使用重绘来重新绘制一个面板,但是我开始制作游戏,并且已经读过重绘在时间方面不可靠。所以我试图制定一个策略,我创建一个BufferedImage,绘制对象图形对象所需的所有东西,然后使用drawImage方法将图像绘制到我的jpanel。

我正在调用dispose来让面板重新渲染,但它只在某些时候工作。以下只是一个例子。如果你继续运行这个程序,BufferedImage只会被绘制~3 / 10次你运行它。有人可以向我解释一下吗?

public class TestMain {

public static void main(String[] args) throws InterruptedException {

    JFrame jf = new JFrame();
    MyPanel mp = new MyPanel();
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jf.setLocation(50, 500);
    jf.add(mp);
    jf.pack();
    jf.setVisible(true);

    mp.draw();
}
}

public class MyPanel extends JPanel {

private static final long serialVersionUID = 1L;

BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d;

public MyPanel() {
    super();
    setPreferredSize(new Dimension(300, 300));
}

public void draw() {
    System.out.println("In draw");
    g2d = (Graphics2D) img.getGraphics();
    g2d.drawString("Test", 10, 10);

    Graphics g = getGraphics();

    g.drawImage(img, 0, 0, this);
    g.dispose();
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    System.out.println("In paintComponent");
}

}

我在幕后与这场比赛中经常发生的事情是什么?我意识到调整窗口大小等会调用重绘并覆盖我的绘图但是当我不这样做时它应该每次出现,不是吗?

编辑:有趣...如果我将draw方法包装在一个连续的while循环中,它就会工作"。但这并没有回答我的问题。我不应该经常回想起这种方法,以给出它绘制正确的错觉。

2 个答案:

答案 0 :(得分:1)

您不应该使用getGraphics()方法进行绘画。使用getGraphics执行的任何代码都只是临时的,并且只要Swing确定需要重新绘制组件,就会丢失,这可能会在这里发生。

重写类的getPreferredSize()方法并调用super.paintComponent(),然后添加System.out.println(...)语句。另外,将一个System.out.println(...)语句添加到draw()方法中以查看代码的执行顺序。

  

我正在调用dispose来让面板重新渲染,

这不会导致面板渲染,它只是释放分配给Graphics对象的资源。您需要调用draw()方法来不断重新绘制。

这与使用Timer连续重绘()组件基本相同。不同之处在于draw()可能会立即发生,但重绘可能需要几毫秒。但是因为每次间隔保持不变时,repaint()需要几毫秒,所以它不像重绘一样会画一次,然后等下一秒。

答案 1 :(得分:1)

我修复了你的代码并获得了以下GUI:

enter image description here

当你在缓冲图像上绘画时,你必须做所有事情。你必须绘制背景并绘制前景。

当您在JPanel的paintComponent方法中绘制缓冲图像时,您所要做的就是绘制图像。

Swing paintComponent方法在Java版本6,7和8中足够快,可以绘制而不会闪烁。我已经完成了成千上万行的动画,没有闪烁。

您必须通过调用SwingUtilities invokeLater方法在Event Dispatch线程上启动Swing应用程序。

这是您修改过的代码。

package com.ggl.testing;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TestMain implements Runnable {

    @Override
    public void run() {
        JFrame jf = new JFrame();
        MyPanel mp = new MyPanel();
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setLocation(50, 50);
        jf.add(mp);
        jf.pack();
        jf.setVisible(true);
        mp.draw();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TestMain());
    }

    public class MyPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        BufferedImage img = new BufferedImage(100, 100,
                BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d;

        public MyPanel() {
            super();
            setPreferredSize(new Dimension(300, 300));
        }

        public void draw() {
            System.out.println("In draw");
            g2d = (Graphics2D) img.getGraphics();
            g2d.setColor(Color.WHITE);
            g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
            g2d.setColor(Color.BLACK);
            g2d.drawString("Test", 30, 50);
            g2d.dispose();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            System.out.println("In paintComponent");
            g.drawImage(img, 0, 0, this);
        }

    }

}