Могу ли я запустить For Loop внутри графического интерфейса? Поскольку в настоящее время у меня есть проблемы с этим, поэтому хотел проверить это, продолжайте давать мне IndexOutofBound
Поскольку я не уверен, как это сделать, поскольку цикл for в графическом интерфейсе, похоже, не запускается, и он продолжает выдавать исключение, я нахожусь в тупике.
Это код
public static class HelpWindow extends JDialog {
JLabel label;
public HelpWindow(JFrame frame) {
super(frame, "Help", true);
setLayout(new FlowLayout());
label = new JLabel("Hey you");
add(label);
}
}
public static class AddQnA extends JDialog {
JLabel label, label2, label3, label4;
JTextField question, answer;
JButton input, reset;
JTextArea textarea;
ArrayList<String> ques = new ArrayList<>();
ArrayList<String> ans = new ArrayList<>();
public AddQnA(JFrame frame) {
super(frame, "Add Question & Answer", true);
setLayout(new FlowLayout());
label = new JLabel("Question :");
add(label);
question = new JTextField(60);
add(question);
label2 = new JLabel("Answer : ");
add(label2);
answer = new JTextField(60);
add(answer);
input = new JButton("Submit");
add(input);
reset = new JButton("Reset");
add(reset);
label3 = new JLabel("Please use the \"x\" on the top right to exit this section");
add(label3);
label4 = new JLabel("");
add(label4);
textarea = new JTextArea(10, 25);
add(textarea);
textarea.setEditable(false);
Reset a = new Reset();
reset.addActionListener(a);
Submit b = new Submit();
answer.addKeyListener(b);
Submit c = new Submit();
input.addActionListener(c);
}
public class Reset implements ActionListener {
@Override
public void actionPerformed(ActionEvent a) {
question.setText("");
answer.setText("");
}
}
public class Submit implements KeyListener, ActionListener {
@Override
public void keyTyped(KeyEvent e) {
// Not in use as of now therefore no method will be here
}
@Override
public void keyPressed(KeyEvent b) {
int keycode = b.getKeyCode();
if (keycode == KeyEvent.VK_ENTER) {
ques.add(question.getText());
ans.add(answer.getText());
label4.setText("**Question & Answer has been Added**");
textarea.append("Question:" + question.getText() + "\n");
textarea.append("Answer:" + answer.getText() + "\n\n");
question.setText("");
answer.setText("");
}
}
@Override
public void keyReleased(KeyEvent e) {
// Not in use as of now therefore no method will be here
}
@Override
public void actionPerformed(ActionEvent c) {
ques.add(question.getText());
ans.add(answer.getText());
label4.setText("**Question & Answer has been Added**");
for (int i = 0; i < ques.size(); i++) {
if (ques.get(i) == null) {
textarea.append("There are no newly added questions or answers");
} else {
textarea.append("Question: " + ques.get(i));
textarea.append("Answer: " + ans.get(i) + "\n");
}
}
question.setText("");
answer.setText("");
}
}
}
public static class DisplayQnA extends JDialog {
JLabel label;
JTextArea textarea;
JMenuBar display;
JMenu file;
JMenuItem show;
ArrayList<String> ques = new ArrayList<>();
ArrayList<String> ans = new ArrayList<>();
public DisplayQnA(JFrame frame) {
super(frame, "Display Question & Answer", true);
setLayout(new FlowLayout());
label = new JLabel("Displaying All Questions And Asnwers");
add(label);
AddQnA qa;
qa = new AddQnA(frame);
textarea = new JTextArea(10, 25);
add(textarea);
textarea.setEditable(false);
for (int i = 0; i < qa.ques.size(); i++) {
if (qa.ques.get(i) == null) {
textarea.append("There are no newly added questions or answers");
} else {
textarea.append("Question: " + qa.ques.get(i));
textarea.append("Answer: " + qa.ans.get(i) + "\n");
}
}
}
}
}
я пытаюсь получить вход в мои массивы AddQnA, а затем извлечь его из DisplayQnA, но, похоже, он не работает вообще. Он просто выскакивает пустую страницу, поэтому мне также было интересно, что, так как и Add, и Display будут открывать свои собственные JFrames, значит, когда я пересекаю Add JFrame, информация о массиве останется или будет удалена?
2 ответа
У вас есть несколько проблем с размещенным кодом, но самая большая проблема, которую я вижу здесь:
public DisplayQnA(JFrame frame) {
// .....
AddQnA qa;
qa = new AddQnA(frame); // ***** Here ****
// ....
}
Я предполагаю, что ваш код первоначально отображает объект AddQnA JDialog, что вы подаете на него иск, чтобы попытаться заполнить вопрос и ответить на ArrayLists, и что после закрытия этого диалогового окна вы затем отображаете диалоговое окно DisplayQnA. В конструкторе DisplayQnA вы создаете совершенно новый объект AddQnA, который полностью отличается от того, который (я считаю) ранее отображался, и тот, который никогда не отображается и поэтому не имеет возможности взаимодействовать с пользователем. Если мое предположение верно (вы не показываете код, в котором фактически отображаете эти объекты), тогда у вас есть проблема с ошибочными предположениями о том, как работают Java и ООП. Ключевая концепция, которую вы упускаете, состоит в том, что объекты класса - это совершенно разные сущности. Да, вы меняете состояние ранее отображенного объекта AddQnA (я думаю), но это не имеет никакого отношения к состоянию объекта AddQnA, который вы создаете в классе DisplayQnA.
Итак, как это решить? Или как решить проблему передачи достоверной информации от одного объекта к другому? Есть несколько возможных решений:
- Вы можете сделать ArrayLists внутри AddQnA
static
так что теперь они являются полями класса, а не объекта, и, таким образом, являются общими для всего приложения. Это простое, прямое и полностью ошибочное решение, так как при этом вы выбрасываете ООП с водой из ванны, а отдельные части вашей программы теряют преимущества структуры ООП (объектно-ориентированного программирования), в том числе сниженную связь, повышенную согласованность., улучшенная тестируемость,... - Вы можете передать информацию через методы установки или конструкторы. Это может сработать.
- Или, что лучше, но потребует больше работы, вы можете попытаться извлечь "модель" вашей программы (данные вопроса / ответа) из ее "представления" (GUI). Это приведет к наиболее надежному решению, которое будет работать лучше всего, если программа масштабируется до чего-то большего, чем просто игрушечная программа, но может оказаться излишним в академических упражнениях.
Поэтому я рекомендую перейти к решению 2 - передавать данные, где и когда это необходимо, с помощью методов установки.
Другие проблемы: избегайте использования KeyListeners в текстовых компонентах. Гораздо лучше создать один ActionListener и добавить его в JTextField, поскольку он будет реагировать на нажатие клавиши ввода.
Например, вы можете отобразить данные в JList и передать модель JList в оба диалоговых окна. Таким образом, диалоговое окно ввода данных может ввести вопрос и ответ в модель, и дисплей данных может отобразить его (или оба могут отобразить его при желании). Например:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class AddDisplay {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
DefaultListModel<QuestionAnswer> qaModel = new DefaultListModel<>();
// both share the same model
EnterDataPanel entryPanel = new EnterDataPanel(qaModel);
DisplayDataPanel displayPanel = new DisplayDataPanel(qaModel);
JDialog enterDialog = new JDialog(null, "Enter Data", ModalityType.MODELESS);
enterDialog.add(entryPanel);
enterDialog.pack();
enterDialog.setLocationByPlatform(true);
JDialog displayDialog = new JDialog(null, "Display Data", ModalityType.MODELESS);
displayDialog.add(displayPanel);
displayDialog.pack();
displayDialog.setLocationByPlatform(true);
displayDialog.setVisible(true);
enterDialog.setVisible(true);
});
}
}
// class to encapsulate a single question/answer pair
class QuestionAnswer {
private String question;
private String answer;
public QuestionAnswer(String question, String answer) {
this.question = question;
this.answer = answer;
}
public String getQuestion() {
return question;
}
public String getAnswer() {
return answer;
}
}
@SuppressWarnings("serial")
class EnterDataPanel extends JPanel {
private static final int COLS = 15;
private JTextField questionField = new JTextField(COLS);
private JTextField answerField = new JTextField(COLS);
private DefaultListModel<QuestionAnswer> qaModel;
private SubmitAction submitAction = new SubmitAction();
public EnterDataPanel(DefaultListModel<QuestionAnswer> qaModel) {
questionField.addActionListener(submitAction);
answerField.addActionListener(submitAction);
this.qaModel = qaModel;
add(new JLabel("Question:"));
add(questionField);
add(Box.createHorizontalStrut(10));
add(new JLabel("Answer:"));
add(answerField);
add(Box.createHorizontalStrut(10));
add(new JButton(submitAction));
}
// abstract action is like an actionlistener "on steroids"
private class SubmitAction extends AbstractAction {
public SubmitAction() {
super("Submit");
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
@Override
public void actionPerformed(ActionEvent e) {
// get text from text fields
String question = questionField.getText().trim();
String answer = answerField.getText().trim();
if (question.isEmpty() || answer.isEmpty()) {
// TODO:
// if either text field is empty, show an error message
} else {
// both text fields hold text
// create a QuestionAnswer object with it
QuestionAnswer qa = new QuestionAnswer(question, answer);
// add into our model and reset fields
qaModel.addElement(qa);
questionField.setText("");
answerField.setText("");
}
questionField.requestFocusInWindow();
}
}
}
@SuppressWarnings("serial")
class DisplayDataPanel extends JPanel {
private static final int ROW_COUNT = 10;
// jlist to display the data
private JList<QuestionAnswer> qajList = new JList<>();
public DisplayDataPanel(ListModel<QuestionAnswer> qaModel) {
qajList.setModel(qaModel);
// set jlist renderer to allow multi-line display
qajList.setCellRenderer(new MyCellRenderer());
// give a protoptype cell value so jlist is wide enough
qajList.setPrototypeCellValue(new QuestionAnswer(
"question question question question question question ",
"answer answer answer answer answer answer "));
qajList.setVisibleRowCount(ROW_COUNT);
JScrollPane qaScroll = new JScrollPane(qajList);
qaScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
setLayout(new BorderLayout());
add(qaScroll);
}
// cell renderer to display multiple lines of text in JList
private class MyCellRenderer extends DefaultListCellRenderer {
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
if (value == null) {
value = "";
} else {
QuestionAnswer qa = (QuestionAnswer)value;
String q = "Q: " + qa.getQuestion();
String a = "A: " + qa.getAnswer();
// use simple HTML formatting to allow multiple lines
value = String.format("<html>%s<br/>%s<html>", q, a);
}
Component superComp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
return superComp;
}
}
}
qa.ques
а также qa.ans
относятся, вероятно, к различным List
s.
Вы перебираете qa.ques
но вы также обращаетесь к qa.ans
во время цикла:
textarea.append("Answer: " + qa.ans.get(i) + "\n");
Как два List
Скорее всего, это относится к двум разным объектам, которые необязательно могут быть заполнены по одним и тем же индексам List
,
Лучше было бы использовать один List
параметризован с помощью пользовательского класса.
Например: List<QuestionAndAnswers> questionAndAnswersList
,
Затем вы можете зациклить:
for (QuestionAndAnswers questionAndAnswers : questionAndAnswersList) {
if (questionAndAnswers == null) {
textarea.append("There are no newly added questions or answers");
} else {
textarea.append("Question: " + questionAndAnswers.getQuestion());
textarea.append("Answer: " + questionAndAnswers.getAnswer() + "\n");
}
}