web-dev-qa-db-fra.com

Comment puis-je changer JPanel à l'intérieur d'un JFrame à la volée?

Pour faire simple, il existe une simple application Java swing composée de JFrame avec certains composants. L'un des composants est un JPanel qui doit être remplacé par un autre JPanel lors de l'action de l'utilisateur.

Alors, quelle est la bonne façon de faire une telle chose? J'ai essayé

panel = new CustomJPanelWithComponentsOnIt();
parentFrameJPanelBelongsTo.pack();

mais cela ne fonctionnera pas. Que suggérerais-tu?

40
yanchenko

Votre cas d'utilisation semble parfait pour CardLayout .

Dans la disposition des cartes, vous pouvez ajouter plusieurs panneaux au même endroit, mais ensuite afficher ou masquer, un panneau à la fois.

51

1) Réglage du premier panneau:

JFrame frame=new JFrame();
frame.getContentPane().add(new JPanel());

2) Remplacement du panneau:

frame.getContentPane().removeAll();
frame.getContentPane().add(new JPanel());

Notez également que vous devez le faire dans le fil de l'événement, pour vous assurer que cela utilise le SwingUtilities.invokeLater ou le SwingWorker

25
Telcontar
frame.setContentPane(newContents());
frame.revalidate(); // frame.pack() if you want to resize.

Rappelez-vous, Java utilisez l'argument 'copier la référence par valeur'. Ainsi, changer une variable ne changera pas les copies de la référence passées à d'autres méthodes.

Notez également que JFrame est très déroutant au nom de l'utilisabilité. L'ajout d'un composant ou la définition d'une disposition (généralement) effectue l'opération dans le volet de contenu. Curieusement, obtenir la disposition vous donne vraiment le gestionnaire de disposition du cadre.

18

J'espère que ce morceau de code vous donnera une idée de la modification de jPanels dans un JFrame.

public class PanelTest extends JFrame {

        Container contentPane;

        public PanelTest()  {
           super("Changing JPanel inside a JFrame");
           contentPane=getContentPane();
        }

        public void createChangePanel() {
           contentPane.removeAll();
           JPanel newPanel=new JPanel();
           contentPane.add(newPanel);
           System.out.println("new panel created");//for debugging purposes
           validate();
           setVisible(true);
        }
}
6
Manoj Fernando

Sur l'action de l'utilisateur:

// vous devez faire quelque chose comme

myJFrame.getContentPane().removeAll()
myJFrame.getContentPane().invalidate()

myJFrame.getContentPane().add(newContentPanel)
myJFrame.getContentPane().revalidate()

Ensuite, vous pouvez redimensionner votre fenêtre selon vos besoins.

5
ShawnD

Tout dépend de la façon dont cela va être utilisé. Si vous souhaitez basculer entre ces deux panneaux, utilisez un CardLayout. Si vous ne passez du premier au second qu'une seule fois (et que vous n'y retournez pas), j'utiliserais la suggestion telcontar et je la remplacerais. Bien que si le JPanel n'est pas la seule chose dans votre cadre, j'utiliserais remove (Java.awt.Component) au lieu de removeAll.

Si vous êtes quelque part entre ces deux cas, c'est essentiellement un compromis espace-temps. Le CardLayout vous fera gagner du temps, mais occupera plus de mémoire en devant garder cet autre panneau en mémoire à tout moment. Mais si vous remplacez simplement le panneau en cas de besoin et que vous le construisez à la demande, vous n'avez pas à garder cette mémoire, mais cela prend plus de temps pour basculer.

Vous pouvez également essayer un JTabbedPane pour utiliser des onglets à la place (c'est encore plus facile que CardLayout car il gère automatiquement l'affichage/le masquage)

3
luke

Problème : Mon composant n'apparaît pas après l'avoir ajouté au conteneur.

Vous devez invoquer revalider et repeindre après avoir ajouté un composant avant qu'il n'apparaisse dans votre conteneur.

Source: http://docs.Oracle.com/javase/tutorial/uiswing/layout/problems.html

1
Arthur Ronald

La réponse layout.replace () existe uniquement/fonctionne sur le GroupLayout Manager.

Les autres LayoutManagers (CardLayout, BoxLayout, etc.) ne prennent PAS en charge cette fonctionnalité, mais vous obligent d'abord à RemoveLayoutComponent (puis à AddLayoutComponent (à nouveau. :-) [Il suffit de remettre les pendules à l'heure])

1
Warren K

J'avais exactement le même problème !! Incroyable !! La solution que j'ai trouvée était:

  1. Ajout de tous les composants (JPanels) au conteneur;
  2. Utiliser la méthode setVisible (false) pour chacun d'eux;
  3. Sur l'action de l'utilisateur, définissez setVisible (true) sur le panneau que je voulais afficher.
// Hiding all components (JPanels) added to a container (ex: another JPanel)
for (Component component : this.container.getComponents()) {
      component.setVisible(false);
}
// Showing only the selected JPanel, the one user wants to see
panel.setVisible(true);

Pas de revalidate (), pas de validate (), pas de CardLayout nécessaire.

1
Gabriel

Les autres personnes ont répondu à la question. Je veux vous suggérer d'utiliser un JTabbedPane au lieu de remplacer le contenu. En règle générale, il est mauvais que les éléments visuels de votre application disparaissent ou soient remplacés par d'autres contenus. Il existe certainement des exceptions à chaque règle, et seuls vous et votre communauté d'utilisateurs pouvez décider de la meilleure approche.

1
James A Wilson
class Frame1 extends javax.swing.JFrame {

    remove(previouspanel); //or getContentPane().removeAll();

    add(newpanel); //or setContentPane(newpanel);

    invalidate(); validate(); // or ((JComponent) getContentPane()).revalidate();

    repaint(); //DO NOT FORGET REPAINT

}

Parfois, vous pouvez faire le travail sans utiliser la revalidation et parfois sans utiliser la repeinture.Je vous conseille d'utiliser les deux.

0
giannis christofakis

Appelez simplement la méthode pack () après avoir défini le ContentPane, (Java 1.7, peut-être plus vieux) comme ceci:

JFrame frame = new JFrame();  
JPanel panel1 = new JPanel(); 
JPanel panel2 = new JPanel(); 
....
frame.setContentPane(panel1);
frame.pack();
...

frame.setContentPane(panel2);
frame.pack();
...
0
Dudu

Je vous suggère d'ajouter les deux panneaux lors de la création du cadre, puis de modifier le panneau visible en appelant setVisible (true/false) sur les deux. Lors de l'appel à setVisible, le parent sera averti et invité à se repeindre.

0
Riduidel