8
votes

Pourquoi la peinture () / PaintComponent () n'a-t-elle jamais été appelée?

Pour les deux derniers jours, j'ai essayé de Comprendre Comment Java gère les graphiques, mais a échoué de manière misérablement. Mon problème principal consiste à comprendre exactement comment et quand la peinture () (ou le nouveau PaintComponent ()) est / doit être appelée.

Dans le code suivant, j'ai fait voir quand les choses sont créées, le PaintComponent () n'est jamais appelé, Sauf si je l'ajoutez manuellement un appel moi-même moi-même ou des appels à jframe.Paintall () / jframe.Painchcomponents ().

J'ai renommé la méthode de peinture () pour peindre () dans l'espoir de réparer ce problème de Il n'est jamais appelé (même à repeindre ()), mais pas de chance. xxx


0 commentaires

5 Réponses :


4
votes

Un problème majeur ici est que vous ne mettez pas à jour vos composants Swing sur le Fil d'expédition d'événement (EDT) . Essayez d'envelopper tout le code dans votre méthode principale dans les éléments suivants:

public static void main(String args[]) throws InterruptedException {
    SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            JFrame frame = new JFrame("Empty JFrame");
            frame.setSize(new Dimension(1000, 500));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            PaintComponentTest ilt = new PaintComponentTest();
            frame.add(ilt);
            frame.setVisible(true);
            ilt.setBackground(Color.BLACK);
        }
    });
}


6 commentaires

Merci, va essayer ça. Mais devrais-je vraiment utiliser SetVisible à la fin pour que cela fonctionne? Le point avec l'appelant tôt était de voir comment je dois gérer l'ajout d'éléments graphiques supplémentaires à une heure ultérieure. Mais toute la chose runnable était nouvelle pour moi; Je n'ai pas vu cela dans aucun des tutoriels que j'ai vus (comme Ce "rel =" Nofollow Noreferrer " > zetcode.com/tatudials/javagamestudial/movingprites/ ... un ).


Utilisation de [ java.awt.eventqueue. ] invoquater Le fait fonctionner pour moi.


(Bien que cela ne soit probablement pas simplement couvrant un bug. Vous devriez revalidate après Ajouter comme décrit dans l'API Docs pour Ajouter .)


Je ne pense pas qu'envelopper sa méthode principale dans une invoquater () serait une bonne idée. Comme il a plusieurs sommets () à là, ce qui ferait accrocher l'EDT


Si vous vouliez vraiment dormir, alors javax.swing.Timer serait la voie à suivre. Mais le code pivotant ne peut pas rester éteint de l'EDT.


Veuillez noter que j'ai pris son thread.sleep () appelle la méthode principale et recommandé la lecture sur les minuteries pour faire l'animation. Le principal objectif de ma réponse était de faire fonctionner les bases, avec des liens de référence à des sujets plus avancés tels que l'animation, le filetage, etc. également au point de Tom, vous n'avez pas besoin d'appeler Revalidate si vous ajoutez le composant avant de le définir visible comme dans mon exemple simplifié. En fin de compte, je me sens comme s'il y a beaucoup de problèmes complexes dans cette question - j'espère que ma réponse aide à préciser ou à préciser de la bonne direction.



2
votes

Je recommande de lire les premiers chapitres de "clients riches sale". J'utilisais Swing depuis des années, mais seulement après avoir lu ce livre, j'ai enfin compris parfaitement comment fonctionne le mécanisme de peinture de Java.


1 commentaires

C'était un bon conseil. Je le lis en fait plus tard. Un livre fantastique, bien que des œuvres d'interface graphique semble une chose de la fin des années quatre-vingt-dix dans ce monde du Web.



11
votes

Une des raisons pour lesquelles la peinture () n'est pas invoquée dans le code d'origine, c'est parce que le composant a une "taille zéro" et le reinkmanger est suffisamment intelligent pour ne pas essayer de peindre quelque chose sans taille.

La raison pour laquelle la réorganisation du code fonctionne est due au fait que lorsque vous ajoutez le composant à la trame, puis rendez le cadre visible que la mise en page est appelée à la mise en page du composant. Par défaut, une image utilise une bordureLayout et par défaut, un composant est ajouté au centre de la bordureLayout qui se produit, donnez tout l'espace disponible sur le composant afin qu'il soit peint.

Cependant, vous modifiez le gestionnaire de mise en page du volet de contenu pour être un flowlayout, vous auriez toujours un problème, car un FlowLayout respecte la taille préférée du composant nulle.

Donc, ce que vous avez vraiment besoin de faire, c'est attribuer une taille préférée à votre composant afin que les gestionnaires de mise en page puissent faire leur travail.


0 commentaires

4
votes

Pour faire Tom Hawtin - Tackline em> heureux. J'ai réécrit à nouveau

Il y a plusieurs choses que j'ai changées (cochez les lignes avec le // nouvelle code> commentaires) frappe> p>

réécrit complètement p>

  • divisé dans un nouveau fichier de composant propre ( ImagEloadTest.java code>) et un fichier pour le tester ( tester.java code>) li> ul>

    Améliorations sur le code d'affiches originaux p>

    • Constructeur d'appel de parent dans ImageloadTest Code> Constructeur ( Super () CODE>) LI>
    • Deuxième constructeur fourni pour définir la liste des images que le composant doit afficher LI>
    • IMPORTANT: appelez à SetPreFerredSize () code> de composant dans le constructeur. Si la taille n'est pas définie, la balançoire ne peint pas votre composant. La taille préférée est basée sur max. Largeur de toutes les images et sur la somme de toutes les hauteur de l'image li>
    • appelez à Super.Paincomponent (g) code> dans la nervation PaintComponent () Code> Li>
    • modifié peintureComponent code> pour baser automatiquement yoffset code> sur la hauteur des images étant dessinées p> li>

    • initialisation de l'interface graphique faite sur EDT P> LI>

    • Comme code d'origine basé sur l'utilisation de Sleep () code> Pour illustrer le chargement et le chargement d'images, cela peut prendre un long temps swingworker code> est utilisé li>
    • travailleur code> attend ensuite un nouveau titre puis chargez des images li>
    • À la fin de l'achèvement du Travailleur Code> Dans DONE () CODE> ajoute enfin le composant au jframe code> et l'affiche. Composant ajouté au volet de contenu de jframe code> comme décrit dans jframe API. Et comme décrit dans Javadoc a apporté l'appel nécessaire à Valider () code> sur jframe code> après appel Ajouter () code>, comme le jframe code > est un conteneur déjà visible qui a changé des enfants. Li> ul>

      citation JAVDOC de Valider () code> p>

      La méthode de validation est utilisée pour provoquer un conteneur pour déposer ses sous-composants de nouveau. Il devrait être invoqué quand cela Les sous-composants du conteneur sont modifiés (ajouté à ou retiré de la conteneur ou mise en page liée à la mise en page informations modifiées) après le Le conteneur a été affiché. P> blockQuote>

      • second travailleur fait juste un peu plus d'attente puis définit la couleur de fond sur le noir li>
      • utilisé jPanel code> comme base de base pour ImagEloadtest CODE> Pour corriger Setbackground () Code> Ce que je ne pouvais pas avoir pour travailler avec jcommonent code>. li> ul>

        Donc, vos principaux problèmes que vous n'avez pas défini la taille préférée du composant et que vous n'avez pas appelé validate () code> sur le jframe code> Après avoir ajouté quelque chose au conteneur déjà visible. P>

        Ceci devrait fonctionner P>

        JPanelPaint / Imageloadtest.java P>

        import java.awt.Dimension;
        import java.awt.Color;
        import java.awt.Image;
        import java.io.File;
        import java.io.IOException;
        import javax.imageio.ImageIO;
        import javax.swing.JFrame;
        import javax.swing.SwingWorker;
        import javax.swing.SwingUtilities;
        import java.util.List;
        import java.util.ArrayList;
        import java.util.concurrent.ExecutionException;
        import jpanelpaint.ImageLoadTest;
        
        public class Tester {
        
          private JFrame frame;
          private ImageLoadTest ilt;
          private final int NUMBEROFFILES = 4;
          private List<Image> list;
        
          //will load the images
          SwingWorker worker = new SwingWorker<List<Image>, Void>() {
            @Override
            public List<Image> doInBackground() throws InterruptedException {
              //sleep at start so user is able to see empty jframe
              Thread.sleep(1000);
              //let Event-Dispatch-Thread (EDT) handle this
              SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                  frame.setTitle("Loading images");
                }
              });
              //sleep again so user is able to see loading has started
              Thread.sleep(1000);
              //loads the images and returns list<image>
              return loadImages();
            }
        
            @Override
            public void done() {
              //this is run on the EDT anyway
              try {
                //get result from doInBackground
                list = get();
                frame.setTitle("Done loading images");
                ilt = new ImageLoadTest(list);
                frame.getContentPane().add(ilt);
                frame.getContentPane().validate();
                //start second worker of background stuff
                worker2.execute();
              } catch (InterruptedException ignore) {}
              catch (ExecutionException e) {
                String why = null;
                Throwable cause = e.getCause();
                if (cause != null) {
                  why = cause.getMessage();
                } else {
                  why = e.getMessage();
                }
                System.err.println("Error retrieving file: " + why);
              }
            }
          };
        
          //just delay a little then set background
          SwingWorker worker2 = new SwingWorker<Object, Void>() {
            @Override
            public List<Image> doInBackground() throws InterruptedException {
              Thread.sleep(1000);
              SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                  frame.setTitle("Setting background");
                }
              });
              Thread.sleep(1000);
              return null;
            }
        
            @Override
            public void done() {
              ilt.setBackground(Color.BLACK);
              frame.setTitle("Done!");
            }
          };
        
          public static void main(String args[]) {
            new Tester();
          }
        
          public Tester() {
            //setupGUI
            SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                frame = new JFrame("Empty JFrame");
                frame.setSize(new Dimension(1000, 500));
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
              }
            });
        
            //start the swingworker which loads the images
            worker.execute();
          }
        
          //create image names
          private String[] createImageFileNames(int count){
            String[] fileNames = new String[count];
            for(int i=0; i < count; i++)
              fileNames[i] = "Cards" + File.separator + (i+1) + ".bmp"; 
            return fileNames;
          }
        
          //load images
          private List<Image> loadImages() {
            List<Image> tmpA = new ArrayList<Image>();
            try {
              for(String name : createImageFileNames(NUMBEROFFILES)){
                System.err.println(name);
                tmpA.add(ImageIO.read(new File(name)));
              }
            } catch (IOException e) { }
        
            return tmpA;
          }
        }
        


3 commentaires

Vous faites toujours des trucs swing sur l'EDT!


Merci d'avoir souligné l'évidence. 8 | Au lieu de me pervoyer parce que j'ai résolu les problèmes réels de l'affiche de la question (images + antécédents ne montrant pas) vous voter pour que quelque chose une autre affiche a déjà expliqué. Je pensais au moins que Bit Oligofren pourrait faire / s'intégrer dans ma solution par lui-même


Wow, gigue, c'est beaucoup de travail pour la fixation d'un simple code de la preuve de concept! Un peu surkill, peut-être, mais un grand merci, de toute façon. J'ai utilisé votre code pour corriger les problèmes principaux dans le code d'origine: 1) ne pas appeler Valider () après une opération ADD () 2) Ne définissez pas la taille préférée du composant. 3) N'appelant pas Super.Painchcomponent () lors de la priorité (cela a fait de l'appel à la retraite (). Après cela, tout fonctionne comme prévu. Modification du poste d'origine pour refléter cela.



3
votes

Ce sont les principaux problèmes avec le code d'origine qui lui faisait ne pas fonctionner:

  1. ne pas appeler valider () après une opération Ajouter ()
  2. Ne pas régler la taille préférée du composant.
  3. ne pas appeler Super.Painchcomponent () lors du remplacement de celui-ci (cela a fait le Setbackground () Appelez non pas de travail)
  4. Je devais hériter de JPanel afin de pouvoir être peint. Ni des composants ni JCOMPONENT ne suffisaient pour l'appel à la mise à niveau () au travail, même lorsque le point de fixation 3.

    Après avoir fait ce qui précède, cela n'a pas vraiment d'importance si vous appelez la méthode de peinture ou de peinture, tous deux semblaient fonctionner aussi longtemps que je me suis souvenu d'appeler le super constructeur au début.

    Cette information a été assemblée à partir de ce que @ Jitter, @tackline et @camickr a écrit, donc Big Kudos!

    P.s. Aucune idée si elle répondait à votre propre question est considérée comme une mauvaise forme, mais que, étant donné que les informations dont j'avais besoin ont été assemblées de plusieurs réponses, je pensais que le meilleur moyen était de mettre en oeuvre les autres réponses et d'écrire une résumée comme ceci.


0 commentaires