Double buffering

0

Witam,

Staram się rozgryźć obsługę double buffering przy prostej animacji w celu wyeliminowania migotania. Przekopałem google i znalazłem przykłady, które staram się z marnym skutkiem wykorzystać. Z tego co się zorientowałem jednym ze sposobów jest przykrycie metody imageUpdate. Skleciłem kod jak poniżej, lecz metoda ta się nie wywołuje. Proszę o pomoc i informację w jaki sposób wywoływana jest ta metoda, a może znacie jakiś lepszy sposób?

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;

/**
 *
 * @author kuba
 */
public class Frame extends JFrame {

    public Frame() {
        super("A frame");

        DrawingArea da = new DrawingArea();

        this.add(da);

        Thread t1 = new Thread(da);
        t1.start();

        this.pack();
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    public class DrawingArea extends Canvas implements Runnable{

        BufferedImage img;
        int x, y;
        int canvasWidth, canvasHeight;
        boolean doneLoading = false;

        public DrawingArea() {
            this.canvasWidth = 600;
            this.canvasHeight = 600;
            this.setPreferredSize(new Dimension(this.canvasWidth, this.canvasHeight));
            x = 0;
            y = 0;
            try {
                img = ImageIO.read(new File("kolko.jpg"));
            } catch (IOException ex) {
            }
        }

        @Override
        public boolean imageUpdate(Image img, int flag, int x, int y, int w, int h) {
            if ((flag & ImageObserver.ALLBITS) != 0) {
                doneLoading = true;
                repaint();
                return false;
            } else {
                return true;
            }
        }

        @Override
        public void paint(Graphics g) {
            if (doneLoading) {
                g.drawImage(img, x, y, null);
            }

        }

        public void run() {
            while (x < canvasWidth - img.getWidth(null) && y < canvasHeight - img.getHeight(null)) {
                x += 1;
                y += 1;
                repaint();
                try {
                    Thread.sleep(10);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Frame.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

        }
    }

    public static void main(String[] args) {
        new Frame();
    }
}
0
@Override
        public void paint(Graphics g) {
            if (doneLoading) {
                g.drawImage(img, x, y, null);
            }

        }

zamiast tego użyj:

@Override
        public void paintComponent(Graphics g) {
            if (doneLoading) {
                g.drawImage(img, x, y, null);
            }

        }

Jest to metoda klasy JPanel,rysuj także np. po Panelu a nie po JFrame

0

Dziękuję za sugestię, ale problem tkwi gdzie indziej. Metoda paint lub paintComponent wywoływana jest z metody imageUpdate() --- natomiast ta nigdy nie zostaje wywołana. Powtórzę moje pytanie: "co" wywołuje metodę imageUpdate ?

0

Dalej nie rozumiem po co chcesz to wiedzieć skoro np. JPanel jest double buffered .

0

imageUpdate jest wywoływana przez klasy Suna implementujące abstrakcyjną klasę Component. Do źródła tych klas legalnie nie dostaniesz się, a tam gdzie klasa jest używana następuje rzut w górę do klasy abstrakcyjnej lub interfejsu, który implementuje ta nieznana bliżej klasa.

Natomiast co do problemu migotania, to nie tak się to rozwiązuje. Pogoogluj za hasłem active rendering. To jest rozwiązanie migotania. Przed jego zastosowaniem trzeba odpalić dla panelu (ogólnie komponentu) metodę setIgnoreRepaint(true); która zlikwiduje odmalowania paint() spowodowane przez ręczne asynchroniczne wymuszenia odmalowania za pomocą repaint(), pozostawiając jedynie odmalowania wymuszone sprzętowo przez zniszczenie zawartości kawałka ekranu i konieczność jego odtworzenia.

Krótko mówiąc aktywny rendering polega na tym, że tworzy się własny wątek, w którym odpala się odmalowywanie ekranu x razy na sekundę, gdzie X jest pożądaną prędkością FPS (ramek na sekundę). Zwykle jest to liczba taka sama lub nieco mniejsza niż częstotliwość odświeżania obrazu w monitorze (szybciej nie ma sensu, a mniej niż 25-30 spowoduje migotanie).
Przykład takiego uproszczonego renderowania można znaleźć w tej książce:
http://fivedots.coe.psu.ac.th/~ad/jg/

0

Active rendering !!!! ----- dzięki za podpowiedź, to rozwiązało mój problem :-)

1 użytkowników online, w tym zalogowanych: 0, gości: 1