web-dev-qa-db-fra.com

JPanel ne met pas à jour jusqu'à ce que redimensionner Jframe

Je sous-classe JPanel pour écraser paintComponent (Graphics), je veux dessiner une image sur jpanel dans un jframe.

Mais mon image ne s'est pas affichée jusqu'à ce que je modifie la taille de jframe . C'est mon code:

public class ImagePanel extends JPanel{

    public void setImage(BufferedImage bi)
    {
        image = bi;
        revalidate();
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        if(image != null)
        {
            g.drawImage(image, 0, 0, this);
        }
    }
}
17
nautilusvn

Vérifiez que vous appelez setVisible()après en ajoutant des composants et en appelant pack() , comme indiqué dans cet exemple } associé _. Vous devrez peut-être également adopter un mise en page approprié. Invoquer repaint(), comme suggéré ici , peut résoudre le symptôme mais pas la cause sous-jacente.

18
trashgod

Si vous voulez "rafraîchir" le JPanel, appelez repaint (), qui appellera paintComponent (). Cela devrait résoudre votre problème:

public void setImage(BufferedImage bi)
{
    image = bi;
    EventQueue.invokeLater(new Runnable()
    {
        public void run()
        {
            repaint();
        }
    });
}

C'est une bonne pratique de mettre à jour et de changer l'interface graphique à l'aide de l'EDT. Voici plus d'infos sur l'EDT si vous êtes intéressé:

Comment fonctionne le thread d'envoi d'événements?

repaint n'a pas besoin d'être appelé depuis l'EST. Si vous modifiez l'interface graphique, par exemple en définissant du texte sur un JLabel, vous devez le placer à l'intérieur de l'EDT. Voici plus d'informations sur ce qui peut être appelé en dehors de l'EDT (avec la permission de Nice cOw):

Est-il sûr d'utiliser Component.repaint () en dehors de l'EDT?

7
John

Jetez un coup d’œil à les docs pour JPanel.add(), dont il hérite de Java.awt.Container:

Ajoute le composant spécifié à la fin de ce conteneur. Il s'agit d'une méthode pratique pour addImpl (Java.awt.Component, Java.lang.Object, int) . Cette méthode modifie les informations relatives à la présentation. Par conséquent, invalide la hiérarchie des composants. Si le conteneur a déjà été affiché, la hiérarchie doit ensuite être validée pour afficher le composant ajouté.

Accentuation ajoutée.

Par conséquent, si vous modifiez un conteneur après que il soit déjà affiché, vous devez appeler validate() pour qu'il s'affiche. Invoquer repaint() n'est pas suffisant. Vous avez peut-être remarqué que l'appel de setVisible(true) fonctionne également; c'est parce que il appelle validate() en interne .

7
Nateowami

J'ai eu le même problème et je l'ai corrigé par l'appel setVisible (true); le JFrame que j'utilisais.

Exemple: si votre JFrame ne se met pas à jour après avoir utilisé:

jframe.setContentPane(new MyContentPane());

le réparer avec:

jframe.setContentPane(new MyContentPane());
jframe.setVisible(true);

Je sais que cela semble idiot de faire cela même si votre JFrame est déjà visible, mais c'est le seul moyen que j'ai trouvé jusqu'à présent pour résoudre ce problème (la solution proposée ci-dessus ne m'a pas fonctionné).

Voici un exemple complet. Exécutez-le puis supprimez le commentaire "f.setVisible (true);" instructions dans les classes Panel1 et Panel2 et vous verrez la différence. N'oubliez pas les importations (Ctrl + Maj + O pour les importations automatiques).

Classe principale:

public class Main {
    private static JFrame f;
    public static void main(String[] args) {
        f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setContentPane(new Panel1(f));
        f.pack();    
        f.setVisible(true);
    }
}

Classe Panel1:

public class Panel1 extends JPanel{
    private JFrame f;
    public Panel1(JFrame frame) {
        f = frame;
        this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
        JButton b = new JButton("Panel 1");
        b.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                f.setContentPane(new Panel2(f));
                // Uncomment the instruction below to fix GUI "update-on-resize-only" problem
                //f.setVisible(true);
            }
        });
        add(b);
    }
}

Classe Panel2:

public class Panel2 extends JPanel{
    private JFrame f;
    public Panel2(JFrame frame) {
        f = frame;
        this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
        JButton b = new JButton("Panel 2");
        b.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                f.setContentPane(new Panel1(f));
                // Uncomment the instruction below to fix GUI "update-on-resize-only" problem
                //f.setVisible(true);
            }
        });
        add(b);
    }
}

J'espère que cela pourra aider.

Cordialement.

3
user2154283

J'ai aussi eu le même problème mais j'ai trouvé une solution. Créez simplement un objet jframe en haut et appelez les méthodes jframe en bas, telles que jf.pack(), jf.setVisible(), jf.setSize(), jf.setDefaultCloseOpetion() devraient figurer au bas de toutes les interfaces utilisateur ajoutées dans ce cadre. 

1