0

I Want to have a JTextArea and a JComboBox, that has some text, and after a while, it changes the text, but for some reason, it's not changing the text for the JTextArea, nor the JComboBox.

Here's the code which is supposed to change the JTextArea and the JComboBox:

      
          //If it's question 1 for the JComboBox

           if (questionNum == 1) {

            //Choices
            choice [0] = "Choice1";
            choice [1] = "Choice2";
            choice [2] = "Choice3";
            choice [3] = "Choice4";

          //If it's Question 2 for the JComboBox

          } else if (questionNum == 2) {

            //Choices
            choice [0] = "Choice1";
            choice [1] = "Choice2";
            choice [2] = "Choice3";
            choice [3] = "Choice4";

          }


          //JTextArea - Questions
          JTextArea Question = new JTextArea(" ");
          Question.setBounds(w/2 - 100, 150, 200, 60);
          Question.setLineWrap(true);
          Question.setWrapStyleWord(true);
          Question.setEditable(false);
          panel.add(Question);


          //If it's question 1

          if (questionNum == 1) {

          Question.setText("Question1");
         
          } else if(questionNum == 2) {
            
            Question.setText("Question2");

          }

          //JCombox - Answer Choices
          answer = new JComboBox(choice);
          answer.setBounds(225, 230, 200, 25);
          panel.add(answer); 
          answer.setVisible(true);
          start.addActionListener(new Window());

What I Tried: I tried to replace the JTextArea with variables, and then tried the Update method, then tried to use the selectAll and replace method, but nothing worked.

I have some more code that changes the question number, in another method.

  • 1
    Best to create and post a decent [mre] with your question. Side note: null layouts and setBounds are not your friends. – Hovercraft Full Of Eels Jul 21 '23 at 17:50
  • Java has this wonderful construct called a getter/setter class. First, create a `Question` class that contains a `String` question and a `List` answers. Now for the tricky part. Each answer causes another question to be asked. So, we add to the `Question` class a `String` previous answer that is empty for initial questions and otherwise contains the answer that led to this question. Lastly, you develop a tree structure with a root Question instance and multiple children Question instances. After you create this application model, then you are ready to create a Swing GUI view. – Gilbert Le Blanc Jul 21 '23 at 19:13
  • 1
    Oracle has a helpful tutorial, [Creating a GUI With Swing](https://docs.oracle.com/javase/tutorial/uiswing/index.html). Skip the Learning Swing with the NetBeans IDE section. – Gilbert Le Blanc Jul 21 '23 at 19:14
  • @GilbertLeBlanc could you please explain to me in greater detail on how I'm supposed to use the list to create a tree structure? As I barely even know what a list is. – Rohan Prabhala Jul 21 '23 at 19:37
  • [How to implement a tree data-structure in Java?](https://stackoverflow.com/questions/3522454/how-to-implement-a-tree-data-structure-in-java) Could you learn to use a search engine to find detailed explanations? – Gilbert Le Blanc Jul 21 '23 at 23:54
  • Again, please post a valid [mre] with your question. It's not fair to force others to create one for you, as the answerer has done. – Hovercraft Full Of Eels Jul 22 '23 at 13:47
  • How is the code that you've posted am MRE? Have you read the link? If not, please study it as it will explain what it is and why it is important. – Hovercraft Full Of Eels Jul 22 '23 at 18:30
  • Again, "minimized code" is not what was requested. Again, it's a [mre] (as per the link). – Hovercraft Full Of Eels Jul 22 '23 at 20:52

1 Answers1

1

Introduction

Since your code was not a minimal runnable example, I went ahead and created the following GUI.

Example

Because this is an example, I only created two answers for each question and I only went two questions deep.

Explanation

Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section.

When I create a Swing GUI, I use the model-view-controller (MVC) pattern. This allows me to separate my concerns and focus on one part of the application at a time.

The model is the major part of this example application. The view and controller are simple because the model is complex.

The model is completely independent of the view and the controller. The view reads a question and answers from the model. The controller gets the next question and answers for the view.

Model

The model consists of four plain Java getter/setter classes.

The first two classes are the ExternalQuestion and the InternalQuestion classes.

The ExternalQuestion class stores a String previous answer, a String question, and a String array of answers. The answer array can be any length. I provided two answers to each question to keep the example short.

Here's the code to load external questions.

        ExternalQuestion eq = new ExternalQuestion(null, 
                "What time do you wake up?",
                "6 am", "8 am");
        addQuestion(eq);
        
        eq = new ExternalQuestion("6 am", 
                "What time do you have breakfast?",
                "7 am", "8 am");
        addQuestion(eq);
        
        eq = new ExternalQuestion("8 am", 
                "What time do you have breakfast?",
                "9 am", "10 am");
        addQuestion(eq);

The first question has a null previous answer. The following questions must have an exact matching previous answer from the prior question. You can create a complex tree with many questions and answers.

This method could be modified to read a text file and create a question tree.

The InternalQuestion class stores an int previous answer index, a String question, and an int array of answer indexes. The answers are kept in a List and the indexes to those answers are stored. This reduces the amount of memory needed for the question tree structure.

The QuestionsModel builds the questions tree using a List for the String answers and a Map for the InternalQuestion instances. This allows an easy transversal through the questions, depending on which answer the user selects.

The AdventureModel stores an instance of the QuestionsModel. Any information needed for a more complex text adventure would be stored here.

View

I created a JFrame and a JPanel. The JPanel uses a GridBagLayout to lay out the Swing components from top to bottom, making each Swing component the same width.

The JFrame has a default BorderLayout. I placed the JPanel in the center of the BorderLayout.

Controller

I used a lambda expression to create an anonymous ActionListener for the JButton. The expression gets the next ExternalQuestion instance and updates the JTextArea and the JComboBox with the question and answers.

Code

Here's the complete runnable code. I made all the additional classes inner classes so I could post the code as one block.

import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;

public class TextAdventureExample implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TextAdventureExample());
    }
    
    private final AdventureModel model;
    
    private JButton button;
    
    private JComboBox<String> comboBox;
    
    private JTextArea textArea;

    public TextAdventureExample() {
        this.model = new AdventureModel();
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("Text Adventure Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        frame.add(createMainPanel(), BorderLayout.CENTER);
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JPanel createMainPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.insets = new Insets(0, 5, 5, 5);
        gbc.gridy = 0;
        
        ExternalQuestion eq = model.getQuestion(null);
        
        JLabel label = new JLabel("Question");
        panel.add(label, gbc);
        
        gbc.gridy++;
        textArea = new JTextArea(5, 30);
        textArea.setEditable(false);
        textArea.setText(eq.getQuestion());
        JScrollPane scrollPane = new JScrollPane(textArea);
        panel.add(scrollPane, gbc);
        
        gbc.gridy++;
        label = new JLabel("Select an answer");
        panel.add(label, gbc);
        
        gbc.gridy++;
        comboBox = new JComboBox<>(eq.getAnswers());
        panel.add(comboBox, gbc);
        
        gbc.gridy++;
        button = new JButton("Submit");
        button.addActionListener(event -> {
            String previousAnswer = (String) comboBox.getSelectedItem();
            updateMainPanel(previousAnswer);
        });
        panel.add(button, gbc);
        
        return panel;
    }
    
    public void updateMainPanel(String previousAnswer) {
        ExternalQuestion eq = model.getQuestion(previousAnswer);
        if (eq == null) {
            button.setEnabled(false);
        } else {
            textArea.setText(eq.getQuestion());
            comboBox.setModel(new DefaultComboBoxModel(eq.getAnswers()));
        }
    }
    
    public class AdventureModel {
        
        private QuestionsModel questionsModel;
        
        public AdventureModel() {
            this.questionsModel = new QuestionsModel();
            loadQuestionsModel();
        }
        
        private void loadQuestionsModel() {
            ExternalQuestion eq = new ExternalQuestion(null, 
                    "What time do you wake up?",
                    "6 am", "8 am");
            addQuestion(eq);
            
            eq = new ExternalQuestion("6 am", 
                    "What time do you have breakfast?",
                    "7 am", "8 am");
            addQuestion(eq);
            
            eq = new ExternalQuestion("8 am", 
                    "What time do you have breakfast?",
                    "9 am", "10 am");
            addQuestion(eq);
        }
        
        private void addQuestion(ExternalQuestion question) {
            questionsModel.addQuestion(question);
        }
        
        public ExternalQuestion getQuestion(String previousAnswer) {
            return questionsModel.getQuestion(previousAnswer);
        }
        
    }

    public class QuestionsModel {

        private final List<String> answers;

        private final Map<Integer, InternalQuestion> questions;

        public QuestionsModel() {
            this.answers = new ArrayList<>();
            this.questions = new HashMap<>();
        }

        public void addQuestion(ExternalQuestion question) {
            int previousIndex = -1;
            String previousAnswer = question.getPreviousAnswer();
            if (previousAnswer != null) {
                previousIndex = getAnswerIndex(previousAnswer);
            }
            int[] indexes = convertAnswersToIndexes(question.getAnswers());
            questions.put(previousIndex, new InternalQuestion(previousIndex,
                    question.getQuestion(), indexes));
        }

        public ExternalQuestion getQuestion(String previousAnswer) {
            int previousIndex = -1;
            if (previousAnswer != null) {
                previousIndex = getAnswerIndex(previousAnswer);
            }
            InternalQuestion iq = questions.get(previousIndex);
            if (iq == null) {
                return null;
            }
            
            String[] output = new String[iq.getAnswers().length];
            for (int index = 0; index < iq.getAnswers().length; index++) {
                output[index] = answers.get(iq.getAnswers()[index]);
            }

            ExternalQuestion eq = new ExternalQuestion(previousAnswer,
                    iq.getQuestion(), output);
            return eq;
        }

        private int[] convertAnswersToIndexes(String[] answers) {
            int[] indexes = new int[answers.length];
            for (int index = 0; index < answers.length; index++) {
                indexes[index] = getAnswerIndex(answers[index]);
            }

            return indexes;
        }

        private int getAnswerIndex(String answer) {
            for (int index = 0; index < answers.size(); index++) {
                String test = answers.get(index);
                if (test.equals(answer)) {
                    return index;
                }
            }

            answers.add(answer);
            return answers.size() - 1;
        }

    }

    public class ExternalQuestion {

        private final String previousAnswer, question;

        private final String[] answers;

        public ExternalQuestion(String previousAnswer, String question,
                String... answers) {
            this.previousAnswer = previousAnswer;
            this.question = question;
            this.answers = answers;
        }

        public String getPreviousAnswer() {
            return previousAnswer;
        }

        public String getQuestion() {
            return question;
        }

        public String[] getAnswers() {
            return answers;
        }

    }

    public class InternalQuestion {

        private final int previousAnswer;

        private final int[] answers;

        private final String question;

        public InternalQuestion(int previousAnswer, String question,
                int... answers) {
            this.previousAnswer = previousAnswer;
            this.question = question;
            this.answers = answers;
        }

        public int getPreviousAnswer() {
            return previousAnswer;
        }

        public int[] getAnswers() {
            return answers;
        }

        public String getQuestion() {
            return question;
        }

    }

}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
Gilbert Le Blanc
  • 50,182
  • 6
  • 67
  • 111
  • @RohanPrabhala: don't apologize. Instead, read the [someone answers link](https://stackoverflow.com/help/someone-answers) and then up-vote the answer if you consider it helpful (as I have done) and check it off as "correct" if it fully answers your question. – Hovercraft Full Of Eels Jul 22 '23 at 20:33
  • @Gilbert Le Blanc This answer is really helpful, and allows me to improve my program a lot, but It doesn't answer the question of, why the JComboBox and the JTextFields, aren't updating when I change the text in them... At least I think, I'm very new to java and so most of the code in the answer is completely new to me, and I barely know how it works. Could you tell me why the swing components won't change/update? – Rohan Prabhala Jul 22 '23 at 21:42
  • @Rohan Prabhala: I don't know what to tell you. My `JTextArea` and `JComboBox` updated just fine. See the `updateMainPanel` method for the code. – Gilbert Le Blanc Jul 22 '23 at 22:21