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

AWT/Swing Java Discussion :

[swing] double buffering hardware et composants


Sujet :

AWT/Swing Java

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2007
    Messages : 12
    Par défaut [swing] double buffering hardware et composants
    Bonjour à tous,

    dans le cadre d'une application de jeu, j'utilise un double-buffer hardware via BufferStrategy dans mon application principale (qui s'étend de JFrame).

    Mon problème est le concept d'affichage.
    Si je fais abstraction de l'utilisation de composants Swing autres que la JFrame et un conteneur dans lequel j'affiche via Java2D toutes les informations de mon jeu (la map, le décor, les persos ...), y a aucun problème.
    Du fait de cette abstraction, je n'ai pas à utiliser de méthode paint et d'ailleurs mon package utilise des fonctions draw que j'ai définies.

    Le problème, c'est si je veux inclure des composants Swing dans mon application. Tout tourne au cauchemar.

    Le début de double-buffering :
    Code java : 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
    private Client(){
     
            // # scène de base
     
            setContentPane(stage = new Stage(this, 800, 600));
     
            // # éléments de la scène
            ...
     
            // stage.fullScreen(defaultDM);
     
            // # écouteurs
            ...
     
            // # fenêtrage (suite)
            pack();
            setResizable(false);
            setVisible(true);
            setSize(800, 600);
     
            // # système visuel
            // double buffering
            createBufferStrategy(2);
            strategy = getBufferStrategy();
            buffer = (Graphics2D)strategy.getDrawGraphics();
            stage.setBuffer(buffer);
            // démarrage de l'application
            stage.start();
        }

    Suit la redéfinition des méthodes d'affichage de JFrame :
    Code java : 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
    public void repaint(int x, int y, int width, int height) {
            display();
        }
     
        public void repaint(long time, int x, int y, int width, int height) {
            display();
        }
     
        public void repaint(long tm) {
            display();
        }
     
        /**
         * @inheritDoc
         */
        public void update(Graphics g){
            display();
        }
     
        /**
         * @inheritDoc
         */
        public void repaint(){
            display();
        }
     
        /**
         * @inheritDoc
         */
        public void paint(Graphics g){
            display();
        }

    Et la dite-méthode display qui permet l'affichage :

    Code java : 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
     
        /**
         * Affiche la scène
         */
        public void display() {
            // assert wx.xyndhra.util.debug.trace("[rendering]");
            // Nettoyage
            if(buffer == null) return;
            // buffer.clearRect(0, 0, getWidth(), getHeight());
     
            // --- ui
            ...
            // Nouvelle image
            GraphicSession.width = getWidth();
            GraphicSession.height = getHeight();
     
            // méthode d'affichage
            // stage.draw(new GraphicSession(buffer));
     
            stage.drawable = true;
            // Affichage des composants
            paintComponents(buffer);
            // stage.drawable = false;
            // Affichage en double-buffering hardware
            strategy.show();
            // assert wx.xyndhra.util.debug.trace(" °--- [end rendering]");
        }

    Ce code ne marche actuellement pas et la raison semble venir du caractère asynchrone de l'affichage de swing.
    paintComponents n'affiche pas les composants...

    mais pire, l'objet Graphics qui est passé à paintComponents n'est pas celui que je reçois dans les méthodes d'affichage paintComponent des dits-composants

    Deux possibilités m'apparaissent (sans savoir comment s'en tirer réellement) :
    1. utiliser la méthode d'affichage direct que j'utilisais, donc sans passer par paintComponents, mais en utilisant draw(new GraphicSession(buffer))
    ... le gros problème est que ça ne prend pas en compte les composants

    2. faire persister l'objet buffer... appeler le strategy.show() plus tard ... non en fait j'ai des doutes sur ce que ça donnerait

    Edit :
    il semblerait que mon problème de visu venait de l'option d'utilisation d'opengl... ça faisait foirer le rendu

    le fait est que maintenant, j'en suis au problème réel, j'ai beau avoir un rendu, il n'est pas bon...

    Affichage saccadé incomplet, ne montre que la scène du jeu, et les composants en train d'être modifiés (comme un textfield qui a le focus) :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // Affichage des composants
    stage.paint(buffer);

    Pour cette version, si j'arrive à trouver comment faire en sorte que mes composants soient complètement affichés, c'est gagné ! (faudrait pouvoir désactiver la vérification des éléments qui ont changé sur le textfield, car je dois le réafficher complètement).

    ---

    Affichage complet, montrant tout, mais avec deux problèmes :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    // Affichage des composants
    paintComponents(buffer);

    Les problèmes sont :
    1. l'objet Graphics2D qui est utilisé par les composants n'est pas l'original... mais surtout, il y a un décalage car mes calculs de position de la souris quant à la position sur les objets / personnages sont erronés, ils semblent être décalé de quelques dizaines de pixels

    2. dès intéraction avec le textfield, ça bloque à presque tous les coups (10 secondes max d'utilisation)... l'application ne plante pas, mais l'affichage freeze complètement (vu que l'affichage est dans un thread séparé, je vois toujours le trace de l'application de base qui elle continue sans problème)

    Soit j'arrive à régler ces problèmes, soit y a plus qu'à recréer des composants genre TextField, mais vu que c'est énorme à faire (rendre compte du comportement d'un composant comme TextField), je préfèrerais régler ces deux problèmes

  2. #2
    Membre Expert
    Avatar de xavlours
    Inscrit en
    Février 2004
    Messages
    1 832
    Détails du profil
    Informations forums :
    Inscription : Février 2004
    Messages : 1 832
    Par défaut
    Bonjour,

    as-tu essayé de ne pas surcharger els méthodes paint, repaint, update ? Dans la FAQ ils n'en font pas mention.
    "Le bon ni le mauvais ne me feraient de peine si si si je savais que j'en aurais l'étrenne." B.V.
    Non au langage SMS ! Je ne répondrai pas aux questions techniques par MP.
    Eclipse : News, FAQ, Cours, Livres, Blogs.Et moi.

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Par défaut
    La surcharge des methodes repaint() tel que tu l'as fait est dangeureux.

    Normalement, repaint poste une demande de redessin, qui sera traité dans l'EDT. Au passage, l'ensemble des demandes pourra etre compacté pour optimiser l'affichage (et ne pas avoir un redessin systématique à chaque modification).
    En bref, repaint est asynchrone.

    La rendre synchrone, tel que tu l'as fait, c'est s'exposer au risque de redessiner à chaque fois que tu modifies un aspect de l'affichage. Par exemple, si tu modifies la couleur d'un textfield, la fonte, le texte etc...

    Par rapport à l'objet Graphics, il faut savoir qu'il n'est pas propagé tel que aux composants. Un clone est créé pour chaque composant, et est translaté pour se mettre dans le systeme de coordonnées du composant. Ne pas propager le Graphics, créer un clone, evite d'avoir à repositionner tous les attributs.

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2007
    Messages : 12
    Par défaut
    Citation Envoyé par Sanguko
    La surcharge des methodes repaint() tel que tu l'as fait est dangeureux.

    Normalement, repaint poste une demande de redessin, qui sera traité dans l'EDT. Au passage, l'ensemble des demandes pourra etre compacté pour optimiser l'affichage (et ne pas avoir un redessin systématique à chaque modification).
    En bref, repaint est asynchrone.
    Il se trouve que oui, les redéfinitions étaient inutiles vu que je n'avais besoin que de redéfinir la méthode paint ^^
    Pour ce qui est du besoin de mise à jour graphique, il est lié aux composants ainsi qu'à la scène du jeu.
    Le fait est que cette partie, si elle devra être optimisée, n'est pas le problème actuel.
    Même la redéfinition des repaint et autre, que j'ai enlevée, n'est pas importante, car elle est faite dans la JFrame hors la JFrame ne gère rien à ce qu'il m'a semblé dans mon environnement si ce n'est la fenêtre.
    Ce qui m'importe ne touche pas à la JFrame mais au contenu dans le JRootPanel, le ContentPane.

    Citation Envoyé par Sanguko
    Par rapport à l'objet Graphics, il faut savoir qu'il n'est pas propagé tel que aux composants. Un clone est créé pour chaque composant, et est translaté pour se mettre dans le systeme de coordonnées du composant. Ne pas propager le Graphics, créer un clone, evite d'avoir à repositionner tous les attributs.
    Mais si un clône est créé, les dessins qui y sont faits se font sur l'élément graphique de base aussi ? (donc la base de dessin n'est pas modifiée, ce serait juste une modification des paramètres relatifs pour le dessin)

    Citation Envoyé par xavlours
    Bonjour,

    as-tu essayé de ne pas surcharger els méthodes paint, repaint, update ? Dans la FAQ ils n'en font pas mention.
    Le problème de l'exemple proposé est qu'il est indépendant du système de composants de swing. Le dessin ne passe pas via paint / repaint / update... et ainsi la question que je me pose est : peut-on utiliser le double-buffering hardware même avec les composants ?

    ---

    Mon problème vient de l'intégration des composants avec le double-buffering hardware. Si j'insère des composants, leur méthode d'affichage sera indépendante du buffer strategy et donc ne sera pas fait via double-buffering hardware, ce que j'aimerai éviter car il deviendrait inutile.

    Ajout :

    http://java.sun.com/docs/books/tutor...rendering.html
    dans les tips, plusieurs semblent intéressants pour mon cas :
    If you use lightweight components, such as Swing components, you may have to fiddle with them a bit so that they draw using your Graphics, and not directly as a result of calling the paint method. Feel free to call Swing methods such as paintComponents, paintComponent, paintBorder, and paintChildren directly from your rendering loop.
    - mon problème au niveau du double-buffering hardware et de l'objet Graphics utilisé

    Feel free to use passive rendering if you just want a simple full-screen Swing or AWT application, but remember that paint events may be somewhat unreliable or unnecessary while in full-screen exclusive mode. Additionally, if you use passive rendering, you will not be able to use more advanced techniques such as page-flipping. Finally, be very careful to avoid deadlocks if you decide to use both active and passive rendering simultaneously--this approach is not recommended.
    - c'est mon cas actuel, les composants utilisent une version passive tandis que ma boucle de rendu est active ...

    Use the setIgnoreRepaint method on your application window and components to turn off all paint events dispatched from the operating system completely, since these may be called during inappropriate times, or worse, end up calling paint, which can lead to race conditions between the AWT event thread and your rendering loop.
    - à voir si c'est la solution à mes problèmes, je ne pense pas car les événements liés aux composants que j'utilise m'importent, e.g. un textfield, faut qu'on voit le texte sélectionné, le déplacement du curseur dessus ...

  5. #5
    Membre émérite
    Profil pro
    Inscrit en
    Février 2007
    Messages
    572
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations forums :
    Inscription : Février 2007
    Messages : 572
    Par défaut
    Citation Envoyé par xion luhnis
    Il se trouve que oui, les redéfinitions étaient inutiles vu que je n'avais besoin que de redéfinir la méthode paint ^^
    Pour ce qui est du besoin de mise à jour graphique, il est lié aux composants ainsi qu'à la scène du jeu.
    Le fait est que cette partie, si elle devra être optimisée, n'est pas le problème actuel.
    Même la redéfinition des repaint et autre, que j'ai enlevée, n'est pas importante, car elle est faite dans la JFrame hors la JFrame ne gère rien à ce qu'il m'a semblé dans mon environnement si ce n'est la fenêtre.
    Ce qui m'importe ne touche pas à la JFrame mais au contenu dans le JRootPanel, le ContentPane.
    L'optimisation dont je parlais etait juste la pour expliquer l'interet du repaint asynchrone.
    Le probleme dans ton code, c'est que tu melanges un peu tous les frameworks, et tu ne respectes pas les règles d'usage. Ca devient compliqué de savoir pourquoi ca ne marche pas.
    La surcharge du repaint pour en faire une methode synchrone etait un probleme.
    Le fait que tu appelles paintComponents() dans un composant Swing en est peut être un également (cf javadoc de JComponent.paint()).

    Citation Envoyé par xion luhnis
    Mais si un clône est créé, les dessins qui y sont faits se font sur l'élément graphique de base aussi ? (donc la base de dessin n'est pas modifiée, ce serait juste une modification des paramètres relatifs pour le dessin)
    Oui. Un Graphics, c'est un peu comme un crayon. D'ailleurs, nommer un Graphics buffer, c'est pas super.

    Citation Envoyé par xion luhnis
    Le problème de l'exemple proposé est qu'il est indépendant du système de composants de swing. Le dessin ne passe pas via paint / repaint / update... et ainsi la question que je me pose est : peut-on utiliser le double-buffering hardware même avec les composants ?
    Je pense que ca devrait marcher.
    Il y a peut être aussi un double buffering par defaut sur les composants swing qu'il faut desactiver. Pas parce que ca fera marcher ton programme, mais plutot parce que c'est inutile dans ton cas.

    ---

    Mon problème vient de l'intégration des composants avec le double-buffering hardware. Si j'insère des composants, leur méthode d'affichage sera indépendante du buffer strategy et donc ne sera pas fait via double-buffering hardware, ce que j'aimerai éviter car il deviendrait inutile.[/QUOTE]

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2007
    Messages : 12
    Par défaut
    Citation Envoyé par Sanguko
    L'optimisation dont je parlais etait juste la pour expliquer l'interet du repaint asynchrone.
    Le probleme dans ton code, c'est que tu melanges un peu tous les frameworks, et tu ne respectes pas les règles d'usage. Ca devient compliqué de savoir pourquoi ca ne marche pas.
    La surcharge du repaint pour en faire une methode synchrone etait un probleme.
    Le fait que tu appelles paintComponents() dans un composant Swing en est peut être un également (cf javadoc de JComponent.paint()).
    Oui, il est clair que n'afficher que ce qu'il faut quand il le faut via le système événementiel est largement mieux.
    Mon problème est autre : le contexte est celui d'un jeu en temps réel, et donc tout va généralement être en mouvement.
    Une chaîne événementielle, c'est bien mais dans mon cas ça serait peut-être inutile et même trop gros. Peut-être vaut-il mieux simplement ne pas passer par les événements mais gérer le tout sous forme d'un rendu complet de la scène, cela chaque x [ms].

    Et le fait est que si ça vaut pour la scène derrière les composants ( là où le jeu se déroule), ça vaut aussi pour les composants vu qu'il faut les redessiner par-dessus.

    Citation Envoyé par Sanguko
    Je pense que ca devrait marcher.
    Il y a peut être aussi un double buffering par defaut sur les composants swing qu'il faut desactiver. Pas parce que ca fera marcher ton programme, mais plutot parce que c'est inutile dans ton cas.
    Mais le Graphics envoyé par swing lors des appels implicites de mise à jour graphique, ce dernier se trouve où ? peut-on le spécifier spécifiquement ?

    Dans mon cas de double-buffering, il faudrait que tout parte du graphic que j'ai obtenu depuis mon bufferstrategy.
    Je pourrais overrider les méthodes qui utilisent l'objet Graphics de base, le remplacer par le bon objet copié depuis celui obtenu depuis bufferstrategy puis laisser le reste se faire.
    Pour cela, il faut cependant que je sache d'où partent les objets Graphics.

    Dans le cas d'un événement de clavier mettant à jour un textfield, le nouveau Graphics vient d'où ? Cela est-il relatif au composant qui a envoyé l'événement où l'objet Graphics part-il toujours depuis la racine (JFrame) ?

  7. #7
    Gfx
    Gfx est déconnecté
    Expert confirmé
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Par défaut
    Question bête : as-tu besoin de ce double-buffering hardware ?

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2007
    Messages : 12
    Par défaut
    Citation Envoyé par Gfx
    Question bête : as-tu besoin de ce double-buffering hardware ?
    Pas par obligation mais le développement du projet va nécessiter une grande vitesse de rendu graphique et donc je me suis imposer de partir avec toutes les possibilités de mon côté.
    Utiliser la carte graphique, si cela est possible, est une possibilité et donc j'essaie de la prendre avec moi.

    Il se trouve qu'actuellement, sans buffering hard, l'image n'a aucun problème de scintillement ou autre si je passe via un buffering soft.

    Peut-être devrait-je plutôt commencer par trouver toutes les méthodes d'accélération du rendu qui existent, les concepts d'architecture graphique qui vont avec mon projet ...
    Dans le pire des cas, changer le système de buffering ne change pas le reste du projet. Il reste que je préfèrerais connaître tous les moyens que j'ai à ma disposition pour accélérer le rendu et vérifier s'ils sont compatibles avec mon projet.

  9. #9
    Gfx
    Gfx est déconnecté
    Expert confirmé
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Par défaut
    Si tu n'en as pas besoin, de n'utilise pas pour le moment

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Juin 2007
    Messages
    12
    Détails du profil
    Informations personnelles :
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2007
    Messages : 12
    Par défaut
    Arf, c'est terrible, en ne l'utilisant pas, les composants fonctionnent et j'ai pu enlever toutes les overrides pour ne plus que définir paintComponent ... c'est plus joli, il faut l'avouer.

    Pour continuer sur ma lancée j'ai implémenter l'utilisation des VolatileImage qui m'a paru plus simple et surtout indépendante du niveau d'implémentation dans la structure des composants.
    Ca fonctionne et ça peut se modifier sans problème.

    Merci

    ... comme quoi faire simple est parfois mieux que faire compliqué

  11. #11
    Gfx
    Gfx est déconnecté
    Expert confirmé
    Avatar de Gfx
    Inscrit en
    Mai 2005
    Messages
    1 770
    Détails du profil
    Informations personnelles :
    Âge : 43

    Informations forums :
    Inscription : Mai 2005
    Messages : 1 770
    Par défaut
    Cela dit c'est pareil pour les VolatileImage. Ça complique le code et le gain n'est pas forcément évident. Assure-toi d'en avoir besoin

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

Discussions similaires

  1. Exemple de Double Buffering Hardware
    Par narkotik dans le forum Codes sources à télécharger
    Réponses: 0
    Dernier message: 09/03/2011, 19h52
  2. Utiliser le double buffering hardware
    Par ilias20 dans le forum Interfaces Graphiques en Java
    Réponses: 2
    Dernier message: 12/06/2010, 23h50
  3. Réponses: 7
    Dernier message: 06/04/2009, 16h43
  4. Double Buffering Hardware -> c'est hard !
    Par myryad dans le forum AWT/Swing
    Réponses: 2
    Dernier message: 24/06/2008, 14h39
  5. [swing & AWT] double buffering hardware
    Par bidules dans le forum AWT/Swing
    Réponses: 6
    Dernier message: 27/11/2005, 11h15

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