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.
Since your code was not a minimal runnable example, I went ahead and created the following GUI.
Because this is an example, I only created two answers for each question and I only went two questions deep.
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.
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.
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
.
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.
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;
}
}
}