Search code examples
javaswingjbuttonactionlistenercardlayout

CardLayout button changes after 6 clicks


I am trying to create a quiz. The quiz starts by reading a file. The file has 6 questions. Each question gets its own card in the cardlayout. Each card has a button to the next CardLayout. Questions 1 - 5 should have a 'next' button that links to the next card. Question 6 should have a button that says 'get results' this will link to a card that displays one of the possible results cards. (these are still in progress, for now I am simply trying to get the button created and am testing it with the .previous() method). As of now each card has a next button and it seems the statement that adds a 'get results' button isn't being reached. take a look.

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ItemListener;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;

public class UserInterface extends JPanel {
    public static final Object QUESTION = "question";
    // fill label with blank text to expand it
    private JLabel resultLabel = new JLabel(String.format("%150s", " "));

    // CardLayout to allow swapping of question panels
    private CardLayout cardLayout = new CardLayout();
    private JPanel centerPanel = new JPanel(cardLayout);
    private List<String> answers = new ArrayList<>();
    private int currentCard = 0; 
    private QuestionsContainer containers = new QuestionsContainer();

    public UserInterface(QuestionsContainer container) throws FileNotFoundException {
        centerPanel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
        for (Questions question : container.getQuestions()) {
            centerPanel.add(createQPanel(question), null);
            currentCard++;

            JPanel bottomPanel = new JPanel(new BorderLayout());

            if ((currentCard == containers.questionsLength() - 1){
                bottomPanel.add(new JButton(new AbstractAction("Next") {
                   @Override
                   public void actionPerformed(ActionEvent e) {
                    cardLayout.next(centerPanel);

                }
            }),
                BorderLayout.LINE_START);
                add(bottomPanel, BorderLayout.LINE_START);
                bottomPanel.add(resultLabel);

                setLayout(new BorderLayout());
                add(bottomPanel, BorderLayout.PAGE_END);
                add(centerPanel);
        }

                JPanel bottomPanel1 = new JPanel();
                bottomPanel1.add(new JButton(new AbstractAction("Get Results") {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        System.out.println("hello");
                        cardLayout.previous(centerPanel);
// both of these are just to see if this statement is reached
                        bottomPanel.validate();
                        bottomPanel.repaint();
                }
            }),
                BorderLayout.LINE_START);
                add(bottomPanel1, BorderLayout.LINE_START);
                bottomPanel1.add(resultLabel);

                setLayout(new BorderLayout());
                add(bottomPanel1, BorderLayout.PAGE_END);
                add(centerPanel);
        }    
    }

    private JPanel createQPanel(Questions question) {

        JPanel radioPanel = new JPanel(new GridLayout(0, 1));
        radioPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
        radioPanel.add(new JLabel(question.getQuestion()), BorderLayout.PAGE_START);
        ButtonGroup buttonGroup = new ButtonGroup();
        ItemListener myItemListener = new MyItemListener(this);
        for (String answer : question.getAnswer()) {
            JRadioButton answerButton = new JRadioButton(answer);

            answerButton.putClientProperty(QUESTION, question);
            answerButton.addItemListener(myItemListener);
            buttonGroup.add(answerButton);
            radioPanel.add(answerButton);
        }

        JPanel qPanel = new JPanel(new BorderLayout());
        qPanel.add(radioPanel);
        return qPanel;
    }

    public void displayResult(String selectedText) {
        resultLabel.setText(selectedText);
    }
    public void displayFinalResults(){

    }
    public static void createAndShowGui() throws FileNotFoundException {

        UserInterface mainPanel = new UserInterface(new QuestionsContainer());

        JFrame frame = new JFrame("User Interface");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

public class QuestionsContainer {

    private List<Questions> questions = new ArrayList<>();
    private int questionCount = 0;  

    QuestionsContainer() throws FileNotFoundException {

        File file = new File("src/house1.txt"); 
        try (Scanner reader = new Scanner(file)) {
            String question = "";
            List<String> answers = new ArrayList<>();

            while (reader.hasNextLine()){


                String line = reader.nextLine();
                if (line.startsWith("QUESTION: ")) {
                    question = line.substring(10);
                } else if (line.startsWith("ANSWER: ")){
                    String answer = line.substring(8);
                    answers.add(answer);
                } else if (line.isEmpty()) {
                    questions.add(new Questions(question, answers));
                    question = "";
                    answers = new ArrayList<>();
                    questionCount++;
                }
            }
        }
    }

    public List<Questions> getQuestions() {
        return questions;
    }
    public int questionsLength(){
        return questions.size();
    }

I've tried making the bottomPanel its own method that returned a bottomPanel. this did not achieve the desired results because it was called in the constructor and I don't think the currentCard variable was adding up every time. Right now this code reads all the questions fine and all the answers fine. But it creates a next button on every single card instead of on the first 5 only. if there's a variable in a weird place or a suspicious print call it's most likely leftover code from a previous test that I forgot to delete/comment out.


Solution

  • You seem to be thinking in terms of a procedural process, rather than an event driven process. The state of currentCard will be updated during each loop, it's state is not "stored" between iterations.

    This means, as a side effect of BorderLayout, only the last component added to the container will be displayed.

    Instead, you need to change your thinking, so that when the ActionListener is triggered, you update the state and make determinations about what should be done, for example

    public UserInterface(QuestionsContainer container) throws FileNotFoundException {
        setLayout(new BorderLayout());
        centerPanel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
        for (Questions question : container.getQuestions()) {
            centerPanel.add(createQPanel(question), null);
        }
        add(centerPanel);
    
        JPanel navigationPane = new JPanel(new GridBagLayout());
        navigationPane.setBorder(new EmptyBorder(8, 8, 8, 8));
        JButton navButton = new JButton("Next");
        navButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent evt) {
                if (evt.getActionCommand().equals("Next")) {
                    currentCard++;
                    if (currentCard == container.questionsLength()) {
                        ((JButton) evt.getSource()).setText("Get results");
                    }
                    cardLayout.next(centerPanel);
                } else {
                    System.out.println("Print the results");
                }
            }
        });
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.anchor = GridBagConstraints.EAST;
        gbc.weightx = 1;
        navigationPane.add(navButton, gbc);
        add(navigationPane, BorderLayout.SOUTH);
    }