2015-05-20 3 views
1

Я пытаюсь удвоить буфер изображения, содержащего многоугольник, в методе paint() с использованием AWT. Используя объект Image для процесса буферизации, я установил черный фон изображения, нарисую многоугольник на изображение, а затем нарисую буферное изображение на экране. Затем я вызываю repaint(), чтобы сделать изображение снова.Непрерывное двойное буферное решение не работает

К сожалению, я по-прежнему получаю артефакты при перекраивании изображения. Что я делаю неправильно?

EDIT: Как примечание стороны, я использую Java 8. EDIT 2: Я звоню repaint() в paint(), потому что нужно непрерывно буфер изображения. Полигон предназначен для перевода по экрану, основанного на пользовательском вводе.

import java.applet.Applet; 
import java.awt.*; 

public class DoubleBuffer extends Applet { 
    int xSize = 900; 
    int ySize = 600; 

    Image bufferImage; 
    Graphics bufferG; 

    @Override 
    public void init() { 
     this.setSize(xSize, ySize); 

     //Double buffering related variables 
     bufferImage = this.createImage(xSize, xSize); 
     bufferG = bufferImage.getGraphics(); 
    } 

    //BUFFERING DONE HERE 
    @Override 
    public void paint(Graphics g){ 
     //drawing images to external image first (buffering) 
     bufferG.setColor(Color.BLACK); 
     bufferG.fillRect(0,0,xSize,ySize); 
     bufferG.setColor(Color.WHITE); 
     bufferG.drawRect(100, 100, 100, 100); 

     //draw the image and call repaint 
     g.drawImage(bufferImage, 0, 0, this); 
     repaint(); 
    } 
} 
+1

Любая причина * не * использовать легкие компоненты (например, JPanel), которые по умолчанию двойной буферизации? (Я бы рекомендовал * not * вызов 'repaint' в методе' paint') – copeg

+0

Как это ни странно, я застрял в использовании компонентов Heavyweight (то есть только в окне) из-за определенных ограничений API, за которыми я следую за работа (пожалуйста, медведь со мной). Если все остальное не удастся, я пойду дальше и использую легкий компонент. Я собираюсь начать еще немного исследований, но что не так с помощью repaint() в paint()? Где еще я должен повторно отобразить свой образ? –

+0

P.S. это работа, связанная с образованием, в которой рендеринг изображений составляет небольшую часть. У меня мало опыта в этой области. –

ответ

2

Проблема заключается в том, что вы не перекрывая update которая является метод, который будет вызываться в ответ на repaint запросы. Для компонентов с тяжелым весом реализация по умолчанию update сначала очистит компонент до цвета фона (может по умолчанию быть белым), а затем вызовите ваш метод paint.

Как указывалось другими, вы не должны звонить repaint с точностью до paint. Вы должны использовать Timer.

После очистки, весь класс будет выглядеть следующим образом:

public class DoubleBuffer extends Applet { 
    int xSize = 900; 
    int ySize = 600; 

    Image bufferImage; 
    Graphics bufferG; 
    Timer timer=new Timer(200, ev->repaint()); 

    @Override 
    public void init() { 
     this.setSize(xSize, ySize); 
    } 

    @Override 
    public void addNotify() { 
     super.addNotify(); 
     //Double buffering related variables 
     bufferImage = this.createImage(xSize, xSize); 
     bufferG = bufferImage.getGraphics(); 
     timer.start(); 
    } 

    @Override 
    public void removeNotify() { 
     super.removeNotify(); 
     bufferImage = null; 
     bufferG = null; 
     timer.stop(); 
    } 


    //BUFFERING DONE HERE 
    @Override 
    public void paint(Graphics g){ 
     //drawing images to external image first (buffering) 
     bufferG.setColor(Color.BLACK); 
     bufferG.fillRect(0,0,xSize,ySize); 
     bufferG.setColor(Color.WHITE); 
     bufferG.drawRect(100, 100, 100, 100); 

     //draw the image and call repaint 
     g.drawImage(bufferImage, 0, 0, this); 
    } 

    @Override 
    public void update(Graphics g) { 
     // now not clearing the background as we expect paint() to fill the entire area 
     this.paint(g); 
    } 
} 
+0

Стоит отметить, что просто вызов 'repaint()' из 'actionPerformed()' (вызванный таймером) служил для меня решением, как я сказал в комментариях к вопросу. Несмотря на это, у меня также есть 'update()' overridden, так как дополнительный (автономный) источник поддерживает ваши претензии. –

+1

@ c4goldsw: это может быть системный побочный эффект. Из-за непредсказуемого времени дублированные операции заполнения могут происходить так быстро, что вы этого не заметите. На моей машине использование таймера значительно уменьшило мерцание, но не полностью устранило его. Поэтому требовалось переопределить «обновление», и я предполагаю, что могут существовать версии систем/Java, где не переопределение «обновления» может иметь еще больший эффект. – Holger

+0

Я ошибался - когда я впервые сообщал о решении copeg как о работе, у меня был таймер, выполняющий очень медленную скорость (один раз в секунду). Увеличение скорости, с которой таймер «тикает», вызывает артефакты, поэтому на самом деле необходимо переопределить и модифицировать update(). –

Смежные вопросы