2015-07-18 2 views
0

J'ai créé une simple boucle qui modifie la quantité de JTextFields et JLabels en fonction de la valeur d'un JSpinner, comme on le voit dans le code suivant:Problème lors de l'utilisation Java Swing dans une boucle for

 public static ArrayList<ArrayList<JTextField>> ChangeQuestionAnswerFields(int numberOfQuestions){ 
     ArrayList<ArrayList<JTextField>> txtFieldArray = new ArrayList<ArrayList<JTextField>>(); 

     JPanel scrollPanel = new JPanel(new GridBagLayout()); 
     //JScrollPane scrollPane = new JScrollPane(scrollPanel); 
     frame.add(scrollPanel, BorderLayout.CENTER); 
     GridBagConstraints c = new GridBagConstraints(); 
     c.gridx = 0; 
     c.gridy = 0; 


     for(int i = 0; i != numberOfQuestions; i++){ 
      JTextField tempQuestion = new JTextField(10); 
      JTextField tempAnswer = new JTextField(10); 
      JLabel tempQuestionHeader = new JLabel("Question " + (i + 1)+ " "); 
      JLabel tempQuestionLbl = new JLabel("Question: "); 
      JLabel tempAnswerLbl = new JLabel("Answer: "); 

      ArrayList<JTextField> tempArrayList = new ArrayList<>(); 
      tempArrayList.add(tempQuestion); 
      tempArrayList.add(tempAnswer); 
      txtFieldArray.add(tempArrayList); 

      c.gridy++; 
      c.gridx = 0; 
      scrollPanel.add(tempQuestionHeader, c); 

      c.gridy++; 
      c.gridx = 0; 
      scrollPanel.add(tempQuestionLbl, c); 

      c.gridx = 1; 
      c.gridwidth = 3; 
      scrollPanel.add(tempQuestion, c); 

      c.gridy++; 
      c.gridx = 0; 
      scrollPanel.add(tempAnswerLbl, c); 

      c.gridx = 1; 
      c.gridwidth = 3; 
      scrollPanel.add(tempAnswer, c); 
     } 
     return txtFieldArray; 
    } 
} 

la valeur du Spinner est introduit dans le procédé et la méthode est appelée au moyen d'un écouteur de modification (où noquestions est la valeur de la JSpinner):

noQuestions.addChangeListener(e -> { 
     ChangeQuestionAnswerFields((int) noQuestions.getValue()); 
     frame.revalidate(); 
     frame.repaint(); 
    }); 

Cette méthode est tout d'abord appelé dans le code lorsque l'écran apparaît d'abord et fonctionne correctement. Cependant, chaque fois que la valeur du spinner change, les étiquettes d'origine et les champs restent à l'écran et d'autres champs de texte apparaissent simplement, ou disparaissent en haut.

http://i.imgur.com/GBY8L3u.png - JSpinner a une valeur de 2 http://i.imgur.com/pSQsA3G.png - JSpinner a une valeur de 3

Est-il possible de résoudre ce problème? Toute aide est très appréciée.

Merci, Tom

minimale Runnable Exemple:

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 
import java.util.ArrayList; 

public class MainGUI { 
    static JFrame frame = new JFrame("Math Reviser"); 

    public static void main(String[] args) { 


     frame.setSize(400, 600); 
     frame.setVisible(true); 

     createScreen(); 
     frame.revalidate(); 
     frame.repaint(); 

    public static void createScreen(){ 
     frame.getContentPane().removeAll(); 

     JSpinner noQuestions = new JSpinner(new SpinnerNumberModel(1, 1, 10, 1)); 
     frame.add(noQuestions, BorderLayout.NORTH); 
     ); 
     changeQuestionAnswerFields(1); 

     frame.revalidate(); 
     frame.repaint(); 

     noQuestions.addChangeListener(e -> { 
      changeQuestionAnswerFields((int) noQuestions.getValue()); 
      frame.revalidate(); 
      frame.repaint(); 
     }); 

    } 

    public static ArrayList<ArrayList<JTextField>> changeQuestionAnswerFields(int numberOfQuestions){ 
     ArrayList<ArrayList<JTextField>> txtFieldArray = new ArrayList<ArrayList<JTextField>>(); 

     JPanel scrollPanel = new JPanel(new GridBagLayout()); 
     frame.add(scrollPanel, BorderLayout.CENTER); 
     GridBagConstraints c = new GridBagConstraints(); 
     c.gridx = 0; 
     c.gridy = 0; 


     for(int i = 0; i != numberOfQuestions; i++){ 
      JTextField tempQuestion = new JTextField(10); 
      JTextField tempAnswer = new JTextField(10); 
      JLabel tempQuestionHeader = new JLabel("Question " + (i + 1)+ " "); 
      JLabel tempQuestionLbl = new JLabel("Question: "); 
      JLabel tempAnswerLbl = new JLabel("Answer: "); 

      ArrayList<JTextField> tempArrayList = new ArrayList<>(); 
      tempArrayList.add(tempQuestion); 
      tempArrayList.add(tempAnswer); 
      txtFieldArray.add(tempArrayList); 

      c.gridy++; 
      c.gridx = 0; 
      scrollPanel.add(tempQuestionHeader, c); 

      c.gridy++; 
      c.gridx = 0; 
      scrollPanel.add(tempQuestionLbl, c); 

      c.gridx = 1; 
      c.gridwidth = 3; 
      scrollPanel.add(tempQuestion, c); 

      c.gridy++; 
      c.gridx = 0; 
      scrollPanel.add(tempAnswerLbl, c); 

      c.gridx = 1; 
      c.gridwidth = 3; 
      scrollPanel.add(tempAnswer, c); 
     } 
     return txtFieldArray; 
    } 
} 
+0

Envisagez de créer et de publier un [exemple de programme minimal exécutable] (http://stackoverflow.com/help/mcve). En outre, cette méthode ne devrait pas être statique. –

+0

@HovercraftFullOfEels La JVM serait-elle suffisamment intelligente pour savoir que l'ArrayList devrait être instanciée en dehors de la boucle, et le faire en conséquence? –

+0

Avez-vous essayé de supprimer le contenu précédent de quelque façon que ce soit? – MadProgrammer

Répondre

2

Utilisation des variables et des méthodes statiques est une indication d'une application mal conçue. Il n'y a pas besoin de variables ou de méthodes statiques. Je vous suggère de lire la section du tutoriel Swing sur How to Use Labels. Le code LabelDemo.java vous montrera comment créer un panneau contenant tous les composants. Ce panneau sera ensuite ajouté au cadre. Ce panneau contiendra également toutes les variables d'instance dont vous avez besoin pour votre programme.

Non seulement l'exemple vous montrera comment créer les composants GUI sur l'EDT, ce que vous devriez toujours faire pour éviter les erreurs aléatoires puisque Swing a été conçu pour être un thread unique. Cependant, le principal problème avec votre code existant est que vous continuez à créer et à ajouter de nouveaux panneaux dans le volet de contenu de l'image. Essayez de changer le spinner à 2 puis redimensionnez le cadre. Ensuite, essayez de changer le spinner à 3 et redimensionner le cadre. Après le redimensionnement, le premier panneau est affiché. En effet, Swing peindra le dernier composant ajouté en premier afin que le premier panneau ajouté soit peint au-dessus du dernier panneau que vous avez créé.

Vous pouvez changer dans votre code existant en supprimant l'ancien panneau avant d'ajouter le nouveau panneau:

static JFrame frame = new JFrame("Math Reviser"); 
static JPanel scrollPanel = new JPanel(); 
... 
frame.remove(scrollPanel); 
//JPanel scrollPanel = new JPanel(new GridBagLayout()); 
scrollPanel = new JPanel(new GridBagLayout()); 

Cependant, je ne recommande pas cette approche. Comme je l'ai d'abord suggéré, vous devez redessiner la classe entière. Lorsque vous faites la refonte, j'utiliserais un BorderLayout sur votre panneau et ensuite vous pouvez ajouter votre spinner à la PAGE_START et ensuite ajouter un JScrollPane au CENTRE du panneau.

Puis, quand vous voulez créer un nouveau panneau vous ajoutez le panneau à l'aide du code scrollpane comme:

scrollPane.setViewportView(scrollPanel); 

Le scrollpane va se rafraîchir et vous n'avez pas à vous soucier de revalidate() ou de repeindre() ou autre chose.