我正在尝试创建个性测验。这个想法是,一个JPanel将显示第一个问题,然后,一旦用户选择了一个单选按钮,第二个JPanel将显示第二个问题。
因为我有5个问题,每个问题有3个答案,所以我认为创建一个创建单选按钮并添加ActionListener
的方法会更快,更高效,但是我很难让听众开始工作。现在,看看它是否有效,我只是想在选择按钮文本时更改它。
我尝试将侦听器添加到createButton
方法中的按钮上,但是我还没有走运。最初,我在方法中将其作为参数,但是没有得到预期的结果,因此我尝试在没有将侦听器作为参数的情况下创建它。插入侦听器作为参数不会更改文本。
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.WindowConstants;
public class UserInterface extends ClickListener implements Runnable
{
private ActionListener listeners;
private JFrame frame;
public UserInterface(){
}
@Override
public void run() {
frame = new JFrame("title");
frame.setPreferredSize(new Dimension(1000, 1000));
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
createComponents(frame.getContentPane());
frame.pack();
frame.setVisible(true);
}
public JFrame getFrame(){
return frame;
}
private void createComponents(Container container){
BoxLayout layout = new BoxLayout(container, BoxLayout.Y_AXIS);
container.setLayout(layout);
container.add(QuizIntro());
container.add(QuestionOne());
container.add(QuestionOneGroup());
}
public JLabel QuizIntro(){
JLabel text = new JLabel("Intro text");
return text;
}
public JLabel QuestionOne(){
JLabel text = new JLabel("1. this is the first question");
return text;
}
public JPanel QuestionOneGroup(){
JRadioButton int1 = createButton("This button was created with my createButton method");
JRadioButton e1 = new JRadioButton("This button was created without that method");
JPanel panel = new JPanel();
panel.add(int1);
panel.add(e1);
return panel;
}
public JRadioButton createButton(String text){
JRadioButton b = new JRadioButton(text);
b.addActionListener(listeners);
return b;
}
}
这是我的动作监听器
public class ClickListener implements ActionListener {
private UserInterface ui;
private JRadioButton b;
@Override
public void actionPerformed(ActionEvent ae) {
if (b.isSelected()){
b.setText("this works");
}
}
}
实际结果是选择了按钮,但文本未更改。我无法弄清楚是否运行了错误的测试以查看我的听众是否正常工作,或者我的听众是否不正常工作。
答案 0 :(得分:4)
您的主要问题在这里:
private ActionListener listeners;
您创建了ActionListener
,但是您从未调用过它。
您还继承自ClickListener
,但从未使用过它。
public class UserInterface extends ClickListener implements Runnable
在您的代码中调用:
b.addActionListener(listeners); //Listeners is null!
因此,您要告诉JRadioButton
拥有一个null
的侦听器。
所以,这里有两种方法:
从程序顶部删除private ActionListener listeners;
并进行更改:
b.addActionListener(listeners);
收件人:
b.addActionListener(this);
从您的班级定义中删除extends ClickListener
并保留:
b.addActionListener(listeners);
但是添加
listeners = new ClickListener();
之前
createComponents(frame.getContentPane());
IMO,我将采用第二种方法。
顺便说一句,ActionListener
实际上可以更改不需要private
变量的文本,而是获取源并将其强制转换。例如:
public void actionPerformed(ActionEvent ae) {
JRadioButton b = (JRadioButton) ae.getSource();
b.setText("this works");
}
忘记提及,请按照Java naming conventions进行操作,以使每个阅读该程序的人都可以更容易阅读和理解。
firstWordLowerCaseVariable
firstWordLowerCaseMethod()
FirstWordUpperCaseClass
ALL_WORDS_UPPER_CASE_CONSTANT
并正确缩进代码:)
答案 1 :(得分:2)
首先,GUI不应扩展侦听器类。不好。最好将它们分开,并在需要时传递引用。例如,如果侦听器需要对GUI的引用,则将其作为参数传递给
此外,您显然想做的就是以有用的行为立即响应JRadioButton选择。我将使用ItemListener而不是ActionListener,因为ItemListener会告诉您是否已选择单选按钮。在ItemEvent上调用getSource()
将为您提供当前选定的JRadioButton。
例如
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
@SuppressWarnings("serial")
public class UserInterface2 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);
public UserInterface2(List<Question> questions) {
centerPanel.setBorder(BorderFactory.createLineBorder(Color.BLUE));
for (Question question : questions) {
centerPanel.add(createQPanel(question), question.getQuestion());
}
JPanel bottomPanel = new JPanel(new BorderLayout());
// add button that allows swapping question panels
bottomPanel.add(new JButton(new AbstractAction("Next") {
@Override
public void actionPerformed(ActionEvent e) {
cardLayout.next(centerPanel);
}
}), BorderLayout.LINE_START);
bottomPanel.add(resultLabel);
setLayout(new BorderLayout());
add(bottomPanel, BorderLayout.PAGE_END);
add(centerPanel);
}
private JPanel createQPanel(Question question) {
JPanel radioPanel = new JPanel(new GridLayout(0, 1));
radioPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
ButtonGroup buttonGroup = new ButtonGroup();
ItemListener myItemListener = new MyItemListener(this);
for (String answer : question.getAnswers()) {
JRadioButton answerButton = new JRadioButton(answer);
// this is present in case you want to extract the Question
// object from the JRadioButton, useful for if you want to
// test if the selected answer is correct
answerButton.putClientProperty(QUESTION, question);
// add our listener to the JRadioButton
answerButton.addItemListener(myItemListener);
// add to button group so only one can be selected
buttonGroup.add(answerButton);
// add to JPanel for display
radioPanel.add(answerButton);
}
JPanel qPanel = new JPanel(new BorderLayout());
qPanel.add(new JLabel(question.getQuestion()), BorderLayout.PAGE_START);
qPanel.add(radioPanel);
return qPanel;
}
// public method that the item listener will use to display selection
public void displayResult(String selectedText) {
resultLabel.setText(selectedText);
}
private static void createAndShowGui() {
// create mock questions
// likely this information will be in a text file
List<Question> questions = new ArrayList<>();
for (int i = 0; i < 10; i++) {
String question = "Question " + i;
List<String> answers = new ArrayList<>();
for (int j = 0; j < 4; j++) {
answers.add(String.format("Answer [%d %d]", i, j));
}
int correctIndex = (int) (Math.random() * answers.size());
// future iteration will also need correctIndex int
questions.add(new Question(question, answers, correctIndex));
}
UserInterface2 mainPanel = new UserInterface2(questions);
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 static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
class MyItemListener implements ItemListener {
private UserInterface2 ui;
public MyItemListener(UserInterface2 ui) {
this.ui = ui;
}
@Override
public void itemStateChanged(ItemEvent e) {
JRadioButton source = (JRadioButton) e.getSource();
String selected = "The JRadioButton " + source.getText();
selected += e.getStateChange() == ItemEvent.SELECTED ? " has been selected"
: " has been unselected";
// to get the actual Question object get the client property:
Question question = (Question) source.getClientProperty(UserInterface2.QUESTION);
// now can get answer Strings and check if correct one selected
System.out.println(question);
String correctAnswer = question.getAnswers().get(question.getCorrectIndex());;
if (source.getText().equals(correctAnswer)) {
selected += " and is correct";
} else {
selected += " and is incorrect";
}
// tell the GUI to display the result
ui.displayResult(selected);
}
}
class Question {
private String question;
private List<String> answers;
private int correctIndex;
public Question(String question, List<String> answers, int correctIndex) {
this.question = question;
this.answers = answers;
this.correctIndex = correctIndex;
}
public String getQuestion() {
return question;
}
public List<String> getAnswers() {
return answers;
}
public int getCorrectIndex() {
return correctIndex;
}
@Override
public String toString() {
return "Question [question=" + question + ", correctIndex="
+ correctIndex + "]";
}
}
答案 2 :(得分:0)
由于您的代码中有许多需要改进的地方,我想我将编写一个示例程序来向您展示如何在Swing中完成这种事情。试试看。 (在此示例代码中,我们几乎也无法改进。但是我只是想保持简单,只解决关键点。)
import javax.swing.*;
import java.awt.event.*;
public class Questions {
public static void main(String[] args) {
JFrame f = new JFrame("Questions");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(new QuestionPanel());
f.setBounds(300, 200, 400, 300);
f.setVisible(true);
}
}
class QuestionPanel extends JPanel implements ActionListener {
private static final String ANSWER_1_TEXT = "Answer 1";
private static final String ANSWER_2_TEXT = "Answer 2";
private static final String ANSWER_3_TEXT = "Answer 3";
private JRadioButton answer1;
private JRadioButton answer2;
private JRadioButton answer3;
QuestionPanel() {
answer1 = new JRadioButton(ANSWER_1_TEXT);
answer2 = new JRadioButton(ANSWER_2_TEXT);
answer3 = new JRadioButton(ANSWER_3_TEXT);
answer1.addActionListener(this);
answer2.addActionListener(this);
answer3.addActionListener(this);
ButtonGroup buttonGroup = new ButtonGroup();
buttonGroup.add(answer1);
buttonGroup.add(answer2);
buttonGroup.add(answer3);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(answer1);
add(answer2);
add(answer3);
}
@Override
public void actionPerformed(ActionEvent e) {
JRadioButton selectedAnswer = (JRadioButton) e.getSource();
if (selectedAnswer == answer1) {
answer1.setText(ANSWER_1_TEXT + " (selected)");
answer2.setText(ANSWER_2_TEXT);
answer3.setText(ANSWER_3_TEXT);
}
else if (selectedAnswer == answer2) {
answer1.setText(ANSWER_1_TEXT);
answer2.setText(ANSWER_2_TEXT + " (selected)");
answer3.setText(ANSWER_3_TEXT);
}
else if (selectedAnswer == answer3) {
answer1.setText(ANSWER_1_TEXT);
answer2.setText(ANSWER_2_TEXT);
answer3.setText(ANSWER_3_TEXT + " (selected)");
}
}
}
答案 3 :(得分:0)
您需要多少个程序员来更换灯泡? 76,1进行更改,75表示他们可以做得更好。
您确实有不好的代码实践,但这通常是因为对语言设计背后的基本概念的理解不明确。因此,我不会评论您的代码对此有何不利之处,仅说明您应该了解的基本知识。
为简化起见,ActionListener
是一个将对ActionPerformedEvent
做出反应的对象。让我们定义一个,称为Observer的类:
观察者不知道是谁生成了该事件,所以告诉他,如果它是一个JRadioButton,让它作为一个事件使用
public class Observer implements ActionListener{
@Override
public void ActionPerformed(ActionEvent ae){
Object source = ae.getSource();
if (source instanceof JRadioButton)
((JRadioButton) source).setText("this works");
}
您的JRadioButton中的任何一个都是不断生成ActionEvent
的对象,但是通常我们不在乎的对象是观察对象,当我们添加ActionListener
时,我们基本上是在说:使这个{{1 }}对象观察我的行为。
所以我们需要一个被观察者和一个观察者,让他们在您的UI(或其简化版本)中进行制作: 由于您尝试使用全局侦听器,因此需要确保那里没有侦听器,因此观察者(我们的ActionListener)目前为null。让我们实例化它这次,我们知道观察者不为空
ActionListener
就这样,当您选择public class UserInterface implements runnable{
private ActionListener observer new Observer();
//...
public void someMethodToCreateButtons(){
JRadioButton observableButton = new JRadioButton("Created here");
observableButton.addActionListener(observer);
}
时,它将文本更改为“ this works”。
这些都是基础知识,现在,我使用这些名称observableButton
和observableButton
是有原因的,ActionListeners基于Observer
,您可以选择一本有关设计模式,您不会后悔。
最后,看来您使自己变得太困难了,请尝试简化逻辑。也许制作一个observer design pattern
包含不同按钮集并在条件为真时显示它?只是在这里吐痰,但请尽量保持简单,希望对您有帮助,祝您好运!