0

我正在使用循环来调用双缓冲绘画。这与覆盖我唯一的 Panel 的重绘方法一起,旨在将重绘的完全控制权传递给我的循环,并且仅在必要时渲染(即在 GUI 中进行了一些更改)。

这是我的渲染例程:

    Log.write("renderer painting");

    setNeedsRendering(false);

    Graphics g = frame.getBufferStrategy().getDrawGraphics();

    g.setFont(font);
    g.setColor(Color.BLACK);
    g.fillRect(0, 0, window.getWidth(),window.getHeight());

    if(frame != null)
        window.paint(g);

    g.dispose();

    frame.getBufferStrategy().show();

如您所见,这是非常标准的。我从缓冲区策略(初始化为 2)中获取 grpahics 对象,将其设为全黑并将其传递给我的“窗口”对象的绘制方法。

使用图形对象完成窗口后,我将其处理并在缓冲区策略上调用 show 以显示虚拟缓冲区的内容。

重要的是要注意,窗口将图形对象传递给填充窗口的许多其他子组件,而每个子组件又使用图形对象的相同实例在屏幕上绘制一些东西:文本、形状或图像。

当系统运行并呈现大图像时,我的问题开始出现。图像似乎被切成几块并一次又一次地绘制(3-4 次),在图像应该渲染的位置内部使用不同的偏移量。请参阅我的附件图片:

这是原始图像: 替代文字 http://img109.imageshack.us/img109/8308/controller.png

这就是我得到的: 替代文字 http://img258.imageshack.us/img258/3248/probv.png

请注意,在第二张图片中,我在图片上渲染形状 - 这些形状始终位于正确的位置。

知道为什么会这样吗?如果我将图像保存到文件中,因为它在内存中,就在调用 g.drawImage(...) 之前它与原始图像相同。

4

1 回答 1

2

呃,你正在使用 Swing 吗?
通常 Swing会自动渲染图像,您无法将其关闭。repaint() 方法是越界的,因为 Swing 有一个非常复杂的渲染例程,这是由于 AWT 小部件的方法兼容性和一些优化,仅在必要时才包含绘图!如果要使用高速绘图 API,请使用带有 BufferStrategy 的组件,例如 JFrame 和 Window,使用

设置忽略重绘(假);

要关闭 Swing 渲染,设置一个绘图循环并绘制内容本身。或者您可以使用 JOGL 进行 OpenGL 渲染。您使用的方法似乎与正确的 Java2D 用法完全不一致。

这里正确使用:

public final class FastDraw extends JFrame {
  private static final transient double NANO = 1.0e-9;


 private BufferStrategy bs;

 private BufferedImage frontImg;

 private BufferedImage backImg;

 private int PIC_WIDTH,
             PIC_HEIGHT;

  private Timer timer;

  public FastDraw() {
    timer = new Timer(true);
    JMenu menu = new JMenu("Dummy");
    menu.add(new JMenuItem("Display me !"));
    menu.add(new JMenuItem("Display me, too !"));
    JMenuBar menuBar = new JMenuBar();
    menuBar.add(menu);
    setJMenuBar(menuBar);

    setIgnoreRepaint(true);
    setVisible(true);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent evt) {
        super.windowClosing(evt);
        timer.cancel();
        dispose();
        System.exit(0);
      }
    });
    try {
      backImg = javax.imageio.ImageIO.read(new File("MyView"));
      frontImg = javax.imageio.ImageIO.read(new File("MyView"));
    }
    catch (IOException e) {
      System.out.println(e.getMessage());
    }
    PIC_WIDTH = backImg.getWidth();
    PIC_HEIGHT = backImg.getHeight();
    setSize(PIC_WIDTH, PIC_HEIGHT);


    createBufferStrategy(1); // Double buffering
    bs = getBufferStrategy();
    timer.schedule(new Drawer(),0,20);
  }
  public static void main(String[] args) {
    new FastDraw();
  }

  private class Drawer extends TimerTask {

    private VolatileImage img;

    private int count = 0;

    private double time = 0;

    public void run() {
      long begin = System.nanoTime();
      Graphics2D  g  = (Graphics2D) bs.getDrawGraphics();
      GraphicsConfiguration gc = g.getDeviceConfiguration();
      if (img == null)
        img = gc.createCompatibleVolatileImage(PIC_WIDTH, PIC_HEIGHT);
      Graphics2D g2 = img.createGraphics();
      // Zeichenschleife
      do {
        int valStatus = img.validate(gc);
        if (valStatus == VolatileImage.IMAGE_OK)
          g2.drawImage(backImg,0,0,null);
        else {
          g.drawImage(frontImg, 0, 0, null);
        }
        // volatile image is ready
        g.drawImage(img,0,50,null);
        bs.show();
      } while (img.contentsLost());
      time = NANO*(System.nanoTime()-begin);
      count++;
      if (count % 100 == 0)
        System.out.println(1.0/time);
    }
  }
于 2010-01-19T21:46:31.263 回答