Java - рисование многих изображений с помощью Graphics.drawImage () и двухэкранной буферной стратегии искажает и обрезает изображения - PullRequest
0 голосов
/ 20 января 2010

Я использую цикл для запуска рисования двойной буферизации.Это, вместе с переопределением моего единственного метода перерисовки 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();

Как видите, это довольно стандартно.Я получаю объект grpahics из буферной стратегии (инициализированный до 2), делаю его все черным и передаю его в метод рисования моего объекта "window".

После того, как окно выполнено с использованием графического объекта, я располагаюи вызовите show в стратегии буфера для отображения содержимого виртуального буфера.

Важно отметить, что окно передает графический объект многим другим дочерним компонентам, заполняющим окно, и каждый из них, в свою очередь, по очереди, использует один и тот же экземпляр графического объекта для рисования чего-либо на экране: текста, фигур или изображений.

Моя проблема начинает проявляться, когда система работает и отображается большое изображение.Изображение выглядит разрезанным на кусочки и рисуется снова и снова (3-4 раза) с различными смещениями внутри того места, где изображение должно быть отображено.Смотрите мои прикрепленные изображения:

Это оригинальное изображение: альтернативный текст http://img109.imageshack.us/img109/8308/controller.png

Вот что я получаю: альтернативный текст http://img258.imageshack.us/img258/3248/probv.png

Обратите внимание, что во второмизображение, я рисую фигуры поверх изображения - они всегда в правильном положении.

Есть идеи, почему это происходит?Если я сохраню изображение в файл, как оно есть в памяти, то перед вызовом g.drawImage (...) оно идентично оригиналу.

1 Ответ

2 голосов
/ 20 января 2010

Э-э, вы используете Swing?
Обычно Swing автоматически отображает изображение, его нельзя отключить. Перекрас () метод находится вне границ, потому что Swing имеет очень сложную процедуру рендеринга из-за совместимость методов для виджетов AWT и несколько оптимизаций, включительно только рисование когда необходимо ! Если вы хотите использовать API высокоскоростного рисования, вы используете компонент с BufferStrategy как JFrame и Window, используйте

setIgnoreRepaint (ложь);

чтобы отключить рендеринг 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);
    }
  }
...