IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 Java Discussion :

paintComponent : conflit entre superposition d'image et repaint() d'images


Sujet :

Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2009
    Messages : 31
    Par défaut paintComponent : conflit entre superposition d'image et repaint() d'images
    Bonjour,

    le titre n'est pas facile à trouver pour ce sujet...

    J'ai créé une carte interactive qui utilise la superposition d'images.
    Chaque image est un object de la classe Item.

    Pour mener à bien la superposition d'images Item, j'ai du utilisé un override de paintComponent() dans une autre classe (Interface.java) puique rien d'autre ne marchait (utiliser des JLabel par exemple, ...).
    Dans cette nouvelle methode paintComponent, j'appel la fonction DrawItem de la classe Item qui dessinera l'image souhaitée grâce à drawImage().

    voici le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    public void paintComponent(Graphics g)
    {
      super.paintComponent(g); //pour empêcher les images avec les "anciennes" propriétés (position notamment) de se redessiner
     
      for(int i = 0; i < vItem.size(); i++)
      {
        vItem.elementAt(i).DrawItem(g);
      }
    }
    tout ceci fonctionne parfaitement, le souci est que lorsque je fait un repaint() dans un autre endroit du code, cette fonction paintComponent est appelée, et du coup redessine TOUTES les images (vItem.elementAt(i))...

    Du coup, lorsque je fais des mouseDragged, ça ralentit consédérablement les mouvements...

    J'espère que vous saurez m'aider à résoudre ce problème...

  2. #2
    Membre Expert
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Par défaut
    Les GUI se font en gros de la façon suivante :
    - disposer les éléments dans la fenêtre
    - afficher la fenêtre

    Finalement, on n'appelle pas les méthodes type paintComponent directement : c'est le système (ici, awt et swing) qui le fait.

    As-tu suivi ce principe ?

  3. #3
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 909
    Billets dans le blog
    54
    Par défaut
    Citation Envoyé par baltam Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    public void paintComponent(Graphics g)
    {
    [...]
      super.paintComponent(g); //pour empêcher les images avec les "anciennes" propriétés (position notamment) de se redessiner
    [...]
    Cela n'a RIEN a voir, les images apparaissent car le Graphics contient encore ce qui a ete rendu/dessine au precedent cycle. En effet par optimisation Swing reutilise le meme Graphics et quand un composant est opaque (isOpaque() retourne true), Swing s'attend a ce que le composant redessine entierement la surface de sa boite englobante avec une couleur opaque et donc ne va pas prendre de temps a reinitialiser le contenu Graphics (d'ou un rendu plus rapide).

    Donc une maniere pour un composant opaque de se dessiner normalement ET correctement est soit :
    • de recouvrir toute sa surface rectangulaire avec un fillRect() d'une couleur opaque.
    • ou d'appeler super.paintComponent() (qui grosso-modo fait la meme chose).


    Ensuite ton probleme de performances, justement c'est car tu n'as pas cherche a optimiser ton rendu. Sinon il fonctionne exactement comme il devrait.

    Lors de ton drag, tu ne dois pas appeler repaint(), mais plutot repaint(x, y, w, h) sur les zones que tu dois redessiner (un premier appel sur la zone du drag avant application des nouvelles coordonnes recues, un second appel sur la zone du drag apres application des nouvelles coordonnees recues, le repaint manager fera l'union des deux zones au moment ou il appelera le paint() du composant au prochain cycle). En contrepartie desormais dans ton paintComponent() tu dois recuperer la zone de clip du Graphics (c'est la zone qui va etre redessinnee par le repaint(x, y, w, h)) et pour chaque image tester si elle intersecte cette zone:
    • si l'image n'intersecte pas la zone de clip, cela ne vaut meme pas la peine de perdre du temps a la redessiner puisque tout ce qui est dessine hors de la zone de clip est perdu (ne s'affichera pas).
    • si l'image intersecte la zone de clip, on la dessine.

    Faire un test ainsi est BEAUCOUP plus rapide que de dessiner toutes les images a chaque fois.

    Si tu as beaucoup beaucoup d'image, le stockage dans une liste n'est pas appropriee ; tu devras t'arranger pour stocker tes images dans une autre collection (un arbre en fonction de leur position a l'ecran par exemple).

    Alternativement tu peux rendre le contenu de ton panel dans une BufferedImage offscreen compatible (voir plus bas) que tu dessinera dans le paintComponent(), comme cela tu ne dessinera qu'une seule et unique image a la fois. Par contre cette methode mange un peu plus de memoire.

    Tu peux aussi faire une solution mixte qui n'utilise l'image offscreen que quand c'est vraiment necessaire histoire d'economiser un peu la memoire.

    Autre optimisation : il te faut convertir tes Image en BufferedImage compatibles histoire de gagner du temps sur leur operation de rendu (une espece de pseudo-acceleration, en fait Java2D ne perd plus de temps a convertir l'image au format de la carte video pour son affichage). Comment utiliser des images compatibles pour améliorer les performances et le rendu ?
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2009
    Messages : 31
    Par défaut
    Hello, merci pour vos réponses

    Pour gifffftane ; oui je pense, je récupère des données d'une base de données, et je dessine en conséquences les images dans le constructeur d'une classe fille de la classe principale qui crée la fenêtre et qui la rend visible...

    après, j'utilise des repaint() pour faire en sorte de mettre à jour les coordonnées des images que je bouge...

    Pour bouye ; merci pour ces explications
    Je vais tenter le repaint(x,y,w,h) ou les Buffered Images compatibles du coup

    Cependant, j'aurais tout de même besoin de déplacer beaucoup d'image d'une seul coup, un peu comme dans Google Maps, mais je ne sais pas s'il y a un moyen d'optimiser les performances du programme (en plus des Buffered Images Compatibles...) ??

    Sinon, après avoir cherché les différents collections, je ne vois pas vraiment ce que je pourrais utiliser d'autre pour stocker mes objets, ou du moins ce que ça changerai si j'utilisais des set ou map ou list, ...

    Je récupère énormément d'information de la base de données, c'est pourquoi j'ai utilisé ce Vector...

    Merci pour votre attention

  5. #5
    Membre Expert
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Par défaut
    Je ne suis pas un spécialiste du drag&drop, mais je m'étonne qu'il faille appeler le repaint pendant le drag, et même au drop. Je dis une bêtise ?

    Et quand au Vector, mieux vaut utiliser un ArrayList, de conception plus moderne (première moitié du 21ème siècle).

    De toutes façons si tu as une base de données, mieux vaut lui laisser faire le travail de stockage, de cache et de mémorisation des images.

  6. #6
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 909
    Billets dans le blog
    54
    Par défaut
    Citation Envoyé par baltam Voir le message
    Cependant, j'aurais tout de même besoin de déplacer beaucoup d'image d'une seul coup, un peu comme dans Google Maps, mais je ne sais pas s'il y a un moyen d'optimiser les performances du programme (en plus des Buffered Images Compatibles...) ??
    Justement, c'est la ou il faut tricher !
    1. optimise de toute maniere le rendu de ton panel comme je te l'ai indique (transformeer chaque image en BufferedImage compatible + zone de clip).
    2. dans le cas d'un DnD... tu crees une BufferedImage compatible aux dimensions de ton panel et... tu dessines ton panel dedans une bonne fois pour toute.

      Et tant que tu dragge ton panel, tu ne fais que deplacer cette image a l'ecran (tu ne rends/dessines pas ton panel de la maniere habituelle). Et quand le DnD est fini, tu liberes/nullifie la reference sur l'image et reprend l'affichage normal.

      Cela permet en plus de faire des effets plus avances comme avoir un ghost semi-transparent du panel lors du DnD (l'image est dessinee une 1ere fois avec un alpha de 1 a la position habituelle du panel et une seconde fois avec une composite d'alpha 0.33~0.5 avec le decallage du DnD)...
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2009
    Messages : 31
    Par défaut
    Hello,

    je comprends très bien le concept de la compatible image, mais j'arrive pas du tout à le faire.

    J'ai créé une fonction qui crée l'image compatible à partir de ce qui se trouve dans mon panel...

    Mais après dans le Drag j'ai essayé de mettre des trucs, mais ça n'apparait pas à l'écran... et du coup je retombe sur le même problème que j'ai eu au tout début de la création de l'application, à savoir tout dessiner à partir du même graphics g de l'override de paintComponents...

    Sinon pour gifffftane, tous les exemples que j'ai pu trouver sur le net ont un repaint()... :$

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    public BufferedImage createCompatibleImage(int x, int y) 
    {
      GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
      BufferedImage image = null;
     
      BufferedImage compatibleImage = gc.createCompatibleImage(sizeWindowX, sizeWindowY); //+getTransparency...
      Graphics g = compatibleImage.getGraphics();
     
      for(int i = 0; i < vItem.size(); i++)
      {
      	try { image = ImageIO.read(new File(vItem.elementAt(i).getPath())); } 
        	catch (IOException e) { e.printStackTrace(); }
    		    	      g.drawImage(image,x,y,vItem.elementAt(i).getLargeur(),vItem.elementAt(i).getHauteur(), this);    
      }
     
      g.dispose();	        
      return compatibleImage;
    }
    Je peux peut être vous envoyer le code par email ?
    Il y a peut être autre chose que je n'ai pas vu... :$

  8. #8
    Membre Expert
    Avatar de gifffftane
    Profil pro
    Inscrit en
    Février 2007
    Messages
    2 354
    Détails du profil
    Informations personnelles :
    Localisation : France, Loire (Rhône Alpes)

    Informations forums :
    Inscription : Février 2007
    Messages : 2 354
    Par défaut
    Plutot que de nous envoyer ton programme, fais-en un extrait en un seul petit fichier source qui compile et s'exécute qui mette en évidence ton problème, et poste le ici, ce sera plus facile pour nous de voir.

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2009
    Messages : 31
    Par défaut
    Le + simple c'est de vous montrer ça :

    Interface.java

    le paintComponents :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public void paintComponent(Graphics g)
    {
      super.paintComponent(g);
     
      for(int i = 0; i < vItem.size(); i++)
      {
        vItem.elementAt(i).DrawItem(g);
      }
     
    }
    Le Drag avec la tentative de création d'image Compatible...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    public BufferedImage createCompatibleImage(int x, int y) 
    {
      GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
     
      BufferedImage image = null;
     
      BufferedImage compatibleImage = gc.createCompatibleImage(sizeWindowX, sizeWindowY); //+getTransparency...
      Graphics g = compatibleImage.getGraphics();
     
      for(int i = 0; i < vItem.size(); i++)
      {
      try { image = ImageIO.read(new File(vItem.elementAt(i).getPath())); } 
      catch (IOException e) { e.printStackTrace(); }
    			    	g.drawImage(image,x,y,vItem.elementAt(i).getLargeur(),vItem.elementAt(i).getHauteur(), this);    
      }
     
      g.dispose();
     
      return compatibleImage;
    }
     
    public void mouseDragged(MouseEvent event)
    {	
    for (int j = 0; j < vItem.size(); j++)
    {	
    vItem.elementAt(j).setX(event.getX()-clickX+vItem.elementAt(j).getInitPosClickX());					   vItem.elementAt(j).setY(event.getY()-clickY+vItem.elementAt(j).getInitPosClickY());
    }
     
    repaint();
    }
    Item.java (l'object image)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public void DrawItem(Graphics g)
    {	
      g.drawImage(img,posX,posY,this.getLargeur(),this.getHauteur(), this);
    }

  10. #10
    Rédacteur/Modérateur

    Avatar de bouye
    Homme Profil pro
    Information Technologies Specialist (Scientific Computing)
    Inscrit en
    Août 2005
    Messages
    6 909
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Information Technologies Specialist (Scientific Computing)
    Secteur : Agroalimentaire - Agriculture

    Informations forums :
    Inscription : Août 2005
    Messages : 6 909
    Billets dans le blog
    54
    Par défaut
    Sauf que la on ne peut pas tester ni se rendre compte des problemes de persformance (qui apparaissent avec combien d'images ? 5 ? 10 ? 100 ? etc. Et puis des images de quelles tailles avec quels modeles de couleur ?)

    Il me semble qu'on peut attacher des fichiers Zip.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
     
    // Chargement des images.
    for(int i = 0; i < vItem.size(); i++) {
      	try { 
                       image = ImageIO.read(new File(vItem.elementAt(i).getPath())); } 
                       image = createCompatibleImage(image); // voir FAQ
                       imageList.add(image);
        	catch (IOException e) { 
                       e.printStackTrace(); 
                  }
    }
     
    BufferedImage offscreen = null;
     
    void createPaneImage() {
      Dimension size = panel.getSize();
      if (offscreen == null || offscreen.getWidth() != size.width || offscreen.getHeight != size.height) {
        GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        offscreen = gc.createCompatibleImage(size.width, size.height); 
      }
      Graphics g = offscreen.createGraphics();
      try {
          renderDirectly(g);
      }
      finally {
         g.dispose();
      } 
    }
     
    protected void paintComponent(Graphics g) {
      Graphics2D g2d = (Graphics2D) g.create();
      try {
        if (isDragging) {
          renderOffscreen(g2d );
        }
        else {
          renderDirectly(g2d );
        }
      }
      finally {
        g2d.dispose();
      }
    }
     
    protected void renderDirectly(Graphics2D g) {
      super.paintComponent(g); // Ou fillRect de la surface();
      Shape clip = g.getClip();
      for (image : imageList) {
         [...]
      }
    }
     
    protected void renderOffscreen(Graphics2D g) {
      if (offscreen == null) {
        createPaneImage();
      }
      g.drawImage(image, 0, 0, null);
      if (dragX != 0 || dragY != 0) {
        g.setComposite(AlphaComposite.SrcOver.derive(0.33);
        g.drawImage(image, dragX, dragY, null);
      }
    }
    Merci de penser au tag quand une réponse a été apportée à votre question. Aucune réponse ne sera donnée à des messages privés portant sur des questions d'ordre technique. Les forums sont là pour que vous y postiez publiquement vos problèmes.

    suivez mon blog sur Développez.

    Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the universe trying to produce bigger and better idiots. So far, the universe is winning. ~ Rich Cook

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Avril 2009
    Messages
    31
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Avril 2009
    Messages : 31
    Par défaut
    Hello !

    Merci pour ces réponses, j'ai appris beaucoup grâce à vous et maintenant ça marche (a priori ).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Conflit entre javascript et script ASP
    Par Mvu dans le forum ASP
    Réponses: 2
    Dernier message: 22/02/2005, 16h28
  2. Possibles conflits entre GL, GLAUX et GLUT
    Par barthelv dans le forum GLUT
    Réponses: 1
    Dernier message: 19/11/2004, 12h31
  3. Conflit entre bases de données
    Par BRODU dans le forum Bases de données
    Réponses: 4
    Dernier message: 18/10/2004, 11h40
  4. conflit entre couleurs
    Par khayyam90 dans le forum OpenGL
    Réponses: 2
    Dernier message: 03/07/2004, 18h00
  5. [Technique] Conflits entre plusieurs requêtes
    Par Neowile dans le forum Décisions SGBD
    Réponses: 3
    Dernier message: 24/03/2003, 09h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo