Swing drawImage() lent animation java

Résolu/Fermé
Hits - Modifié le 9 févr. 2018 à 08:29
 Hits - 9 févr. 2018 à 16:55
Bonsoir,

Dans le cadre d'un projet je m'entraine a faire des animations simples avec Swing. Le but ici étant de faire défiler l'image vers la gauche, cela marche mais ça saccade pas mal, je ne sais pas si c'est normal ou si il y a moyen d'optimisé la chose,
le code est un test seulement, c'est pour ca que j'ai tout mis dans la meme classe avec une classe interne, je vous laisse le code intégrale et le lien de l'image à télécharger et a mettre à la racine du projet pour faire le test si nécéssaire.
(je n'ai pas un pc surpuissant mais j'ai vérifier et le processeur est utilisé à a peine 20% durant l'execution de mon programme)

lien de l'image que j'utilise : (à enregistrer sous le nom de background.png) :
http://www.1explore.net/gamedesign3/assets/scrollingBackground.png

code :
package testingIG;

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MoveBack extends JFrame {
 
 PanBack p;
 
 public MoveBack () {
  setTitle("Test"); // titre de la fenetre
  setSize(900,700); // taille quand elle s'ouvre
  setMinimumSize(new Dimension(700, 500));
  setResizable(true); // peut etre redimensionnée
  setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // fin processus fenetre quand "x" appuyer
  p = new PanBack(this);
  setContentPane(p);
  setVisible(true); // rend la fenetre visible
 }
 
 public void run () {
  p.run();
 }
 
 public static void main (String [] args) {
  EventQueue.invokeLater(new Runnable() {
   public void run () {
    MoveBack m = new MoveBack();
    m.run();
   }
  });
 }
 
 class PanBack extends JPanel {
  
  int x;
  BufferedImage img;
  MoveBack frame;
  
  public PanBack (MoveBack m) {
   frame = m;
   try {
    img = ImageIO.read(new File("background.png"));
   }
   catch (Exception e) {
    e.printStackTrace();
   }
  }
  
  public void paintComponent(Graphics g) {
   g.drawImage(img, x, 0,img.getWidth(), getHeight(), null);
   x -= 1;
  }
  public void run () {
   Thread t = new Thread () {
    public void run() {
     while (true) {
      try {
       Thread.sleep(10);
       frame.repaint();
      }
      catch (Exception e) {}
     }
    }
   };
   EventQueue.invokeLater(()->t.start());
  }
 }
}


Merci par avance à ceux qui prendront le temps de jeter un oeil.

A voir également:

1 réponse

KX Messages postés 16733 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 31 janvier 2024 3 015
9 févr. 2018 à 14:05
Bonjour,

Il y aurait pas mal de choses à revoir dans ton code, mais en testant chez moi ça ne saccade pas, donc peu importe les modifications que je pourrais faire, ce sera à l'aveugle, sans savoir si c'est mieux ou pire.

Bref, en Swing il ne faut pas faire de Thread, mais plutôt des SwingUtilities.invokeLater() et/ou des SwingWorker (inutile dans ton cas).
De plus au lieu de faire des boucles while avec des Thread.sleep, il vaut mieux utiliser un Scheduler.
Quand à ton int x, puisqu'il peut-être modifié par plusieurs Thread, un AtomicInteger serait pertinent.
Enfin, il n'y a aucune raison de manipuler un JPanel ici, un Container suffirait.

Exemple :

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

class DynamicBackgroundContainer extends Container {

    private static final long serialVersionUID = 1L;

    private final AtomicInteger x;
    private final BufferedImage img;

    public DynamicBackgroundContainer(BufferedImage img, long period) {
        this.img = img;
        x = new AtomicInteger(0);
        ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
        scheduler.scheduleAtFixedRate(this::scheduledMove, 0, period, TimeUnit.MILLISECONDS);
    }

    private void scheduledMove() {
        x.decrementAndGet();
        SwingUtilities.invokeLater(this::repaint);
    }

    @Override
    public void paint(Graphics g) {
        g.drawImage(img, x.get(), 0, img.getWidth(), this.getHeight(), null);
    }
}

public class MoveBack extends JFrame {

    private static final long serialVersionUID = 1L;

    public MoveBack() throws IOException {
        setTitle("Test"); // titre de la fenetre
        setSize(900, 700); // taille quand elle s'ouvre
        setMinimumSize(new Dimension(700, 500));
        // setResizable(true); // peut etre redimensionnée
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // fin processus fenetre quand "x" appuyer
        BufferedImage img = ImageIO.read(new File("background.png"));
        setContentPane(new DynamicBackgroundContainer(img, 10));
        setVisible(true); // rend la fenetre visible
    }

    public static void main(String[] args) throws IOException {
        new MoveBack();
    }
}
0
Ok merci de ta réponse en tout cas, je vais jeter un oeil à tout ça.
C'est très étrange quand même car j'ai l'impression que mon pc à des problèmes de lag avec java (particulierement swing j'ai l'impression), deja sur un autre projet j'avais ce type de problème alors qu'en faisant les test sur d'autres pc (dont certains moins puissant) cela marchait toujours parfaitement.. pourtant j'ai une install classique du JDK 1.8 sur unbuntu 17.10 (HP) , je vais essayer de voir si certains on ce type de problèmes...
0
après trois heures de recherche j'ai trouvé la solution, cela est du à certaines version d'ubuntu qui créent un délai entre les appels successifs de repaint et l'affichage sur l'écran, du coup il suffit ce mettre cette ligne apres le repaint :
Toolkit.getDefaultToolkit().sync();
ça résous totalement le problème et c'est fluide du coup,
source : https://stackoverflow.com/questions/33257540/java-window-lagging-on-ubuntu-but-not-windows-when-code-isnt-lagging

Merci à toi en tout cas !
0