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

Composants Java Discussion :

repaint vs paintImmediately


Sujet :

Composants Java

  1. #1
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    60
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 60
    Par défaut repaint vs paintImmediately
    Bonjour,

    Pour faire une animation d'un JPanel descendant, j'ai un Timer avec pour action le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    setOpaque(false);
    repaint(getVisibleRect());
    setOpaque(true);
    setSize(getWidth(), (getProgressInPercent() * getParent().getHeight()) / 100);
    repaint();
    Déjà ce code me plaît moyennement car je suis obligé de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    setOpaque(false);
    repaint(getVisibleRect());
    setOpaque(true);
    juste pour redessiner le composant parent sans le panel en question... On peut pas garder une trace du Graphics correspondant au composant parent avant l'ajout du fils et le faire dessiner quand on en a besoin ?

    Enfin bref, ce n'est pas l'origine de mon post, voici mon problème :
    le premier repaint ne fait strictement rien, alors que si à la place je mets
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    paintImmediately(getVisibleRect());
    là ça fonctionne mais avec du clipping très désagréable

    Donc j'aimerais bien savoir pourquoi le premier repaint marche pas

    Si quelqu'un a une idée je suis tout ouïe !
    Merci d'avance à tous ceux qui se pencheront sur mon problème !

  2. #2
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    60
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 60
    Par défaut
    J'ai trouvé un exemple plus simple à mettre en œuvre si vous voulez tester :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    setOpaque(false);
    paintImmediately(getVisibleRect());
    setOpaque(true);
    setBackground(new Color(getBackground().getRed(), getBackground().getGreen(), getBackground().getBlue(),
    	2*e.getProgressInPercent()));
    Donc comme ça ça marche mais avec du clipping et maintenant de cette manière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    setOpaque(false);
    repaint(getVisibleRect());
    setOpaque(true);
    setBackground(new Color(getBackground().getRed(), getBackground().getGreen(), getBackground().getBlue(),
    	2*e.getProgressInPercent()));
    Là ça fait clairement n'importe quoi

    En fait je soupçonne les "optimisations" lors d'un appel à repaint d'être responsables de tout ça...

    Programs should not invoke paintImmediately() directly unless there is a valid need for real-time painting. This is because the asynchronous repaint() will cause multiple overlapping requests to be collapsed efficiently, whereas direct calls to paintImmediately() will not.

  3. #3
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    60
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 60
    Par défaut
    Je vous mets ci-dessous les artefacts que j'obtiens avec paintImmediately car je croyais que c'était du clipping mais en fait on dirait plus un problème de rafraichissement vertical, non ?


  4. #4
    Membre Expert
    Avatar de slim_java
    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2008
    Messages
    2 272
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : Tunisie

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2008
    Messages : 2 272
    Par défaut
    salut.
    est ce que je peux comprendre pourquoi tu met un

    suivit d'un

    de plus quel est l'update JRE que tu utilise et appartement l'ordre d'exécution de la méthode paintComponent est important. en fait quel est le code que tu as écrit dedans ?

  5. #5
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    repaint, comme le dit la javadoc, ça demande au composant de se redessiner, ça ne veux pas dire que le composant sera redessiné à la sortie. En pratique, ton code est équivalent à

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    setOpaque(false);
    setOpaque(true);
    repaint(getVisibleRect());

    Quand à paintImmediately, tu ne peux pas l'appeler depuis ton timer, sauf si c'est un timer swing.

  6. #6
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    60
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 60
    Par défaut
    Tout d'abord merci de vous pencher sur mon problème !

    Pour te répondre slim_java, je fais ça pour redessiner l'herbe, que tu vois sur l'image que j'ai mise, sans le panel courant. En fait je suis obligé de le faire car sinon il redessine sur ce qu'il avait déjà dessiné auparavant et ça rend n'importe quoi
    Après pour ta question sur "l'update JRE que j'utilise", ben euh... je comprends pas bien ce que tu veux savoir J'utilise soit update() soit update(Rectangle), mais je ne sais pas si c'est la réponse que tu attendais ?
    Et pour paintComponent dans le second exemple je ne l'ai pas touchée


    Merci tchize_ pour ta précision, je comprends mieux pourquoi il fait rien alors
    Et c'est bien un timer Swing, donc pas de problème normalement alors ?


    Donc la question qui subsiste est : d'où viennent ces foutus artefacts ?

  7. #7
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    il faudrait voir le contenu de ta méthode paint Mais j'ai l'impression que t'essaie de te casser la tête dans le mauvais sens. La logique voudrait, pour une animation que tu gère toi même.

    1) Ecrire ta méthode paint pour qu'elle dessine en fonction de l'étape courante de l'animation
    2) écrire ton timer pour que, par exemple, 20 fois par seconde il fasse avancer l'étape courante de l'animation et appelle repaint() ou repaint(int x, int y, int width, int height) (qui s'exécutera dès que possible). Bref le timer n'a pas à dessiner plusieurs fois sur une seule action.

    L'utilisation de getVisibleRect() est une bonne idée car ça te permet de ne redessiner que la partie visible.

  8. #8
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    60
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 60
    Par défaut
    Et bien tchize_ je te remercie vraiment car maintenant avec ta méthode ça marche (presque) nickel !
    Je dis presque parce que je chipote et qu'il y a encore de très légers artefacts mais faut vraiment forcer l'œil

    Par contre, je voudrais juste savoir, il n'y a pas d'autres moyens de faire redessiner le composant parent sans le composant courant autrement que ce que je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    setOpaque(false);
    paintImmediately(getVisibleRect());
    setOpaque(true);

    Encore merci tchize_ en tout cas !

  9. #9
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    le parent, quand il se redessine, aura inévitablement besoin de demander à ses enfants de se redessiner, parce que ceuxci peuvent aussi avoir changé d'etat, parce qu'il faut bien les dessiner sinon on ne le vois pas, et parce qu'il ne garde pas un cache de ce à quoi les enfants ressemblent. Donc oui, redessiner le parent implique redessiner tous les enfants qui sont présent dans la zone à redessiner. Et comme déjà dit, tu n'a pas besoin d'appeler paintimmediately, c'est mentionner dans la doc: "vous ne devriez jamais avoir besoin de l'appeler". Pose toi plutot la questoin de pourquoi ce opaque te pose problème, normalement on s'amuse pas à changer à tout bout de champ cette valeur.

  10. #10
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    60
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 60
    Par défaut
    "vous ne devriez jamais avoir besoin de l'appeler sauf en cas de besoin de dessiner en temps réel" ce qui est mon cas ! Parce que dans le cadre d'une animation on est bien obligés de redessiner tout ou une partie du composant courant avant de dessiner l'animation à l'instant t.
    C'est uniquement pour ça que je fais le truc avec setOpaque et paintImmediately : pour redessiner le composant à l'état initial ; ensuite après je dessine l'animation pour l'étape courante. Et si j'utilise setOpaque plutôt que setVisible, qui paraîtrait plus logique, c'est tout simplement qu'avec ce dernier ça marche pas


    J'explique ma démarche : je veux faire apparaître un panel par dessus un autre panel avec un effet de fondu.
    Donc pour ça j'ai un timer swing qui va mettre à jour la couleur de fond du panel avec une valeur de plus en plus opaque, et qui demande au composant de se redessiner avec la nouvelle couleur de fond :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    step++;
    bgColor = new Color(getBackground().getRed(), getBackground().getGreen(), getBackground().getBlue(),
    		step*5); //valeur de la transparence : + élevée + opaque
    repaint(getVisibleRect());
    Ensuite dans la méthode paintComponent de mon panel j'ai mis ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    protected void paintComponent(Graphics g) {
    	if(this.isOpaque()) {
    		//on efface le panel courant
    		this.setOpaque(false);
    		this.paintImmediately(getVisibleRect());
    		this.setOpaque(true);
     
    		//on change la couleur d'arrière-plan
    		g.setColor(bgColor);
    		Rectangle r = this.getVisibleRect();
    		g.fillRect(r.x, r.y, r.width, r.height);
    	}
    }

    Si tu as une autre solution je suis vraiment tout ouïe, mais pour l'instant personnellement je n'ai pas trouvé d'autre solution qui marche

  11. #11
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    Citation Envoyé par S(ô.Ô)B Voir le message
    Ensuite dans la méthode paintComponent de mon panel j'ai mis ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    protected void paintComponent(Graphics g) {
    	if(this.isOpaque()) {
    		//on efface le panel courant
    		this.setOpaque(false);
    		this.paintImmediately(getVisibleRect());
    		this.setOpaque(true);
     
    		//on change la couleur d'arrière-plan
    		g.setColor(bgColor);
    		Rectangle r = this.getVisibleRect();
    		g.fillRect(r.x, r.y, r.width, r.height);
    	}
    }
    Appeler paintIlmmediately sur sois même alors qu'on est déjà en train de se dessiner ? Quel est l'intérêt. Tu veuux effacer le composant et faire son dessin par défaut? Appelle super.paintComponent() qui fera le nettoyage. Pas étonnant que t'aie besoin de chipoter avec ton setOpaque. Tu n'a pas besoin de paintImmediately, ce que tu as besoin, c'est d'apprendre à écrire une méthode paintComponent correct. setOpaque ça permet de savoir si tu veux ou non que le composant laisse l'arrière plan (conteneur donc) visible. C'est le cas de JLabel, par exemple, qui laissent passer la couleur du conteneur au travers du texte.


    Je le répète, pour faire une animation

    Un timer qui fait avancer l'animation (index temporel + déplacement éventuel de composant si ceci est prévue) et instruit swing qu'il faut se redessiner le composant (repaint(region)).

    Une méthode paint ou paintComponent qui dessine l'étape courante. paintimmediately n'est absolument pas invoqué là. Exemple avec une boule qui tourne:
    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
    public class Main {
        public static class Animation extends JPanel{
            private int step = 0;
            public void nextStep(){
                step = ++step%1000;
            }
     
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                int x = (int)(Math.sin(Math.PI*step/50)*(getWidth()-10)/2.0)+getWidth()/2;
                int y = (int)(Math.cos(Math.PI*step/50)*(getHeight()-10)/2.0)+getHeight()/2;
                g.setColor(new Color(100,0,(255*step)/1000));
                g.fillOval(x-5, y-5, 10, 10);
            }
     
        }
        public Animation anim = new Animation();
        public Main(){
            final JFrame f = new JFrame("animation");
            f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            f.getContentPane().add(anim,BorderLayout.CENTER);
            f.setSize(300,200);
            f.getContentPane().setBackground(new Color(100,0,255));
            anim.setOpaque(false);
            anim.setDoubleBuffered(false);
            f.setVisible(true);
            Timer t = new Timer(1000/50, new ActionListener() {
     
                public void actionPerformed(ActionEvent e) {
                    anim.nextStep();
                    f.repaint();
                }
            });
            t.start();
        }
      public static void main(String[] _args)
        {
          new Main();
        }
     
    }

  12. #12
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    60
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 60
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Appeler paintIlmmediately sur sois même alors qu'on est déjà en train de se dessiner ? Quel est l'intérêt. Tu veuux effacer le composant et faire son dessin par défaut? Appelle super.paintComponent() qui fera le nettoyage.
    J'aimerais bien, mais ça ne marche pas...
    Si j'en suis arrivé à cette "bidouille" c'est bien que j'ai essayé pas mal de trucs "propres" avant

  13. #13
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 483
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 483
    Par défaut
    comme le montre l'exemple que je t'ai donné, faire une animation c'est pas compliqué. Maintenant, si tu nous donnais le code de ton timer, le code de ton composant et que tu décrit ce que t'essaie de faire comme animation on devrais t'aider.

  14. #14
    Membre averti
    Inscrit en
    Mars 2009
    Messages
    60
    Détails du profil
    Informations forums :
    Inscription : Mars 2009
    Messages : 60
    Par défaut
    Ah ben tiens grâce à ton exemple j'ai trouvé ce qui allait pas, en fait il fallait seulement rajouter setOpaque(false) à mon panel... Je croyais que ça l'était par défaut pour les panels ? M'enfin tant pis, maintenant tout roule !

    Merci pour ton aide tchize_

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

Discussions similaires

  1. [JPanel] paint, paintComponent et repaint ?
    Par Pill_S dans le forum Composants
    Réponses: 8
    Dernier message: 08/02/2013, 18h38
  2. Lancer repaint() en synchrone
    Par Higestromm dans le forum Interfaces Graphiques en Java
    Réponses: 11
    Dernier message: 06/10/2005, 14h40
  3. [MouseEvent] arret de souris = repaint() ?
    Par n00bi dans le forum AWT/Swing
    Réponses: 3
    Dernier message: 08/06/2005, 12h38
  4. Comment geler le repaint d'un TPageControl ?
    Par qi130 dans le forum Composants VCL
    Réponses: 19
    Dernier message: 20/12/2004, 23h30
  5. [Graphisme][Débutant(e)] Problème sur repaint()
    Par Katyucha dans le forum AWT/Swing
    Réponses: 6
    Dernier message: 08/10/2004, 18h12

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