【问题标题】:Why is my JLabel not showing up为什么我的 JLabel 没有出现
【发布时间】:2015-09-04 16:39:44
【问题描述】:

我在我的一个抽象类中调用了这个名为 check 的方法,但由于某种原因,我添加到 JPanel(面板)的 JLabel(问题)没有显示出来。 为什么会出现这种情况?任何解释,我都在使用 repaint 和 validate 方法,但仍然没有任何显示。

【问题讨论】:

  • 请提供MCVESSCCE,我们可以复制粘贴并查看与您相同的问题。此代码需要通过删除一些不必要的变量、添加库等来修复。请帮助我们帮助您。
  • 你的代码让我担心,要么你违反了 Swing 的单线程规则,要么用 yr while 循环和 thread.sleep 阻塞 EDT,要么从 EDT 的上下文之外修改 UI跨度>

标签: java swing jpanel jbutton jlabel


【解决方案1】:

您遇到的问题是您阻塞了事件调度线程,阻止更新 UI 或处理任何新事件...

从这里开始……

        for(int i = 0; i < 15; i++)
        {
             //...
            
            //Check to see if user has enetered anything
            // And is compounded here
            while(!answered)
            {
                Thread.sleep(duration);
                //...
            }           

您显然是在以一种程序化的方式思考(就像您对控制台程序一样),但这不是 GUI 的工作方式,GUI 是事件驱动的,在某个时间点发生某些事情并且您会做出响应。

我的建议是调查 Swing Timer,这将允许您安排在某个时间点的回调,并在触发时执行一些操作,这可用于修改 UI,因为它执行在 EDT 的范围内。

请参阅Concurrency in SwingHow to use Swing Timers 了解更多详情

我还建议您查看CardLayout,因为它可能更容易在不同视图之间更改

更多详情请见How to Use CardLayout

基础知识

我非常遵守“代码到接口而不是实现”的原则和Model-View-Controller。这些基本上鼓励您分离和隔离责任,因此一个部分的更改不会对另一部分产生不利影响。

这也意味着您可以即插即用实现,解耦代码并使其更加灵活。

从基础开始,你需要一些包含文本(问题)、正确答案和一些“选项”(或错误答案)的东西

public interface Question {

    public String getPrompt();
    public String getCorrectAnswer();
    public String[] getOptions();
    public String getUserResponse();
    public void setUserResponse(String response);
    public boolean isCorrect();

}

所以,非常基本。该问题有提示、正确答案、一些错误答案,并且可以管理用户响应。为了方便使用,它还有一个isCorrect方法

现在,我们需要一个实际的实现。这是一个非常基本的示例,但您可能有许多不同的实现,甚至可能包括用于答案类型的泛型(为了论证,我假设为 String

public class DefaultQuestion implements Question {

    private final String prompt;
    private final String correctAnswer;
    private final String[] options;

    private String userResponse;

    public DefaultQuestion(String prompt, String correctAnswer, String... options) {
        this.prompt = prompt;
        this.correctAnswer = correctAnswer;
        this.options = options;
    }

    @Override
    public String getPrompt() {
        return prompt;
    }

    @Override
    public String getCorrectAnswer() {
        return correctAnswer;
    }

    @Override
    public String[] getOptions() {
        return options;
    }

    @Override
    public String getUserResponse() {
        return userResponse;
    }

    @Override
    public void setUserResponse(String response) {
        userResponse = response;
    }

    @Override
    public boolean isCorrect() {
        return getCorrectAnswer().equals(getUserResponse());
    }
}

好的,这一切都很好,但这实际上对我们有什么作用?好吧,知道你可以创建一个简单的组件,它的唯一工作就是向用户提出问题并处理他们的响应......

public class QuestionPane extends JPanel {

    private Question question;

    public QuestionPane(Question question) {
        this.question = question;

        setLayout(new BorderLayout());

        JLabel prompt = new JLabel("<html><b>" + question.getPrompt() + "</b></html>");
        prompt.setHorizontalAlignment(JLabel.LEFT);

        add(prompt, BorderLayout.NORTH);

        JPanel guesses = new JPanel(new GridBagLayout());
        guesses.setBorder(new EmptyBorder(5, 5, 5, 5));
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;
        gbc.weightx = 1;
        gbc.anchor = GridBagConstraints.WEST;

        List<String> options = new ArrayList<>(Arrays.asList(question.getOptions()));
        options.add(question.getCorrectAnswer());
        Collections.sort(options);

        ButtonGroup bg = new ButtonGroup();
        for (String option : options) {
            JRadioButton btn = new JRadioButton(option);
            bg.add(btn);

            guesses.add(btn, gbc);
        }

        add(guesses);

    }

    public Question getQuestion() {
        return question;
    }

    public class ActionHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            getQuestion().setUserResponse(e.getActionCommand());
        }

    }

}

这是一个很好的可重用组件,它可以处理一堆问题而不关心。

现在,我们需要一些方法来管理多个问题,一个测验!

public class QuizPane extends JPanel {

    private List<Question> quiz;

    private long timeOut = 5;
    private Timer timer;
    private JButton next;

    private CardLayout cardLayout;
    private int currentQuestion;

    private JPanel panelOfQuestions;

    private Long startTime;

    public QuizPane(List<Question> quiz) {
        this.quiz = quiz;
        cardLayout = new CardLayout();
        panelOfQuestions = new JPanel(cardLayout);

        JButton start = new JButton("Start");
        start.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                currentQuestion = -1;
                nextQuestion();
                timer.start();
            }
        });
        
        JPanel filler = new JPanel(new GridBagLayout());
        filler.add(start);
        panelOfQuestions.add(filler, "start");

        for (int index = 0; index < quiz.size(); index++) {
            Question question = quiz.get(index);
            QuestionPane pane = new QuestionPane(question);
            panelOfQuestions.add(pane, Integer.toString(index));
        }
        panelOfQuestions.add(new JLabel("The quiz is over"), "last");
        currentQuestion = 0;
        cardLayout.show(panelOfQuestions, "start");

        setLayout(new BorderLayout());
        add(panelOfQuestions);

        JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        next = new JButton("Next");
        buttonPane.add(next);
        next.setEnabled(false);

        add(buttonPane, BorderLayout.SOUTH);

        next.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                nextQuestion();
            }
        });

        timer = new Timer(250, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (startTime == null) {
                    startTime = System.currentTimeMillis();
                }
                long duration = (System.currentTimeMillis() - startTime) / 1000;
                if (duration >= timeOut) {
                    nextQuestion();
                } else {
                    long timeLeft = timeOut - duration;
                    next.setText("Next (" + timeLeft + ")");
                    next.repaint();
                }
            }
        });
    }

    protected void nextQuestion() {
        timer.stop();
        currentQuestion++;
        if (currentQuestion >= quiz.size()) {
            cardLayout.show(panelOfQuestions, "last");
            next.setEnabled(false);
            // You could could loop through all the questions and tally
            // the correct answers here
        } else {
            cardLayout.show(panelOfQuestions, Integer.toString(currentQuestion));
            startTime = null;
            next.setText("Next");
            next.setEnabled(true);
            timer.start();
        }
    }
}

好的,这有点复杂,但最基本的是,它管理当前向用户呈现的问题、管理时间并允许用户导航到下一个问题(如果他们愿意)。

现在,很容易迷失在细节中……

这部分代码实际上设置了主“视图”,使用CardLayout

panelOfQuestions.add(filler, "start");

for (int index = 0; index < quiz.size(); index++) {
    Question question = quiz.get(index);
    QuestionPane pane = new QuestionPane(question);
    panelOfQuestions.add(pane, Integer.toString(index));
}
panelOfQuestions.add(new JLabel("The quiz is over"), "last");
currentQuestion = 0;
cardLayout.show(panelOfQuestions, "start");

start 按钮、“结束屏幕”和每个单独的QuestionPane 都添加到由CardLayout 管理的panelOfQuestions,这使得根据需要“翻转”视图变得容易。

我用一个简单的方法转到下一个问题

protected void nextQuestion() {
    timer.stop();
    currentQuestion++;
    if (currentQuestion >= quiz.size()) {
        cardLayout.show(panelOfQuestions, "last");
        next.setEnabled(false);
        // You could could loop through all the questions and tally
        // the correct answers here
    } else {
        cardLayout.show(panelOfQuestions, Integer.toString(currentQuestion));
        startTime = null;
        next.setText("Next");
        next.setEnabled(true);
        timer.start();
    }
}

这基本上增加了一个计数器并检查我们是否已经用完了问题。如果我们有,它会禁用下一个按钮并向用户显示“最后一个”视图,如果没有,它会移动到下一个问题视图并重新启动超时计时器。

现在,“魔法”来了……

timer = new Timer(250, new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        if (startTime == null) {
            startTime = System.currentTimeMillis();
        }
        long duration = (System.currentTimeMillis() - startTime) / 1000;
        if (duration >= timeOut) {
            nextQuestion();
        } else {
            long timeLeft = timeOut - duration;
            next.setText("Next (" + timeLeft + ")");
        }
    }
});

Swing Timer 是一个伪循环,这意味着它将在常规基础上调用 actionPerformed 方法,就像 forwhile 循环一样,但它这样做的方式很遥远,以至于它没有'不要阻止 EDT。

这个例子增加了一点“魔力”,因为它充当倒计时计时器,它检查问题对用户可见的时间并显示倒计时,直到它自动移动到下一个问题,当duration 大于或等于 timeOut(本例中为 5 秒),它调用 nextQuestion 方法

但是你问你如何使用它?您创建Questions 的List,创建QuizPane 的实例并将其添加到屏幕上显示的其他容器中,例如...

public class QuizMaster {

    public static void main(String[] args) {
        new QuizMaster();
    }

    public QuizMaster() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                List<Question> quiz = new ArrayList<>(5);
                quiz.add(new DefaultQuestion("Bananas are:", "Yellow", "Green", "Blue", "Ping", "Round"));
                quiz.add(new DefaultQuestion("1 + 1:", "2", "5", "3", "An artificial construct"));
                quiz.add(new DefaultQuestion("In the UK, it is illegal to eat...", "Mince pies on Christmas Day", "Your cousin", "Bananas"));
                quiz.add(new DefaultQuestion("If you lift a kangaroo’s tail off the ground...", "It can’t hop", "It will kick you in the face", "Act as a jack"));

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new QuizPane(quiz));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

}

最后,因为我知道你会想要一个完全可运行的示例

import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class QuizMaster {

    public static void main(String[] args) {
        new QuizMaster();
    }

    public QuizMaster() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                List<Question> quiz = new ArrayList<>(5);
                quiz.add(new DefaultQuestion("Bananas are:", "Yellow", "Green", "Blue", "Ping", "Round"));
                quiz.add(new DefaultQuestion("1 + 1:", "2", "5", "3", "An artificial construct"));
                quiz.add(new DefaultQuestion("In the UK, it is illegal to eat...", "Mince pies on Christmas Day", "Your cousin", "Bananas"));
                quiz.add(new DefaultQuestion("If you lift a kangaroo’s tail off the ground...", "It can’t hop", "It will kick you in the face", "Act as a jack"));

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new QuizPane(quiz));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class QuizPane extends JPanel {

        private List<Question> quiz;

        private long timeOut = 5;
        private Timer timer;
        private JButton next;

        private CardLayout cardLayout;
        private int currentQuestion;

        private JPanel panelOfQuestions;

        private Long startTime;

        public QuizPane(List<Question> quiz) {
            this.quiz = quiz;
            cardLayout = new CardLayout();
            panelOfQuestions = new JPanel(cardLayout);

            JButton start = new JButton("Start");
            start.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    currentQuestion = -1;
                    nextQuestion();
                    timer.start();
                }
            });
            
            JPanel filler = new JPanel(new GridBagLayout());
            filler.add(start);
            panelOfQuestions.add(filler, "start");

            for (int index = 0; index < quiz.size(); index++) {
                Question question = quiz.get(index);
                QuestionPane pane = new QuestionPane(question);
                panelOfQuestions.add(pane, Integer.toString(index));
            }
            panelOfQuestions.add(new JLabel("The quiz is over"), "last");
            currentQuestion = 0;
            cardLayout.show(panelOfQuestions, "start");

            setLayout(new BorderLayout());
            add(panelOfQuestions);

            JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.RIGHT));
            next = new JButton("Next");
            buttonPane.add(next);
            next.setEnabled(false);

            add(buttonPane, BorderLayout.SOUTH);

            next.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    nextQuestion();
                }
            });

            timer = new Timer(250, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (startTime == null) {
                        startTime = System.currentTimeMillis();
                    }
                    long duration = (System.currentTimeMillis() - startTime) / 1000;
                    if (duration >= timeOut) {
                        nextQuestion();
                    } else {
                        long timeLeft = timeOut - duration;
                        next.setText("Next (" + timeLeft + ")");
                        next.repaint();
                    }
                }
            });
        }

        protected void nextQuestion() {
            timer.stop();
            currentQuestion++;
            if (currentQuestion >= quiz.size()) {
                cardLayout.show(panelOfQuestions, "last");
                next.setEnabled(false);
                // You could could loop through all the questions and tally
                // the correct answers here
            } else {
                cardLayout.show(panelOfQuestions, Integer.toString(currentQuestion));
                startTime = null;
                next.setText("Next");
                next.setEnabled(true);
                timer.start();
            }
        }
    }

    public interface Question {

        public String getPrompt();

        public String getCorrectAnswer();

        public String[] getOptions();

        public String getUserResponse();

        public void setUserResponse(String response);

        public boolean isCorrect();
    }

    public class DefaultQuestion implements Question {

        private final String prompt;
        private final String correctAnswer;
        private final String[] options;

        private String userResponse;

        public DefaultQuestion(String prompt, String correctAnswer, String... options) {
            this.prompt = prompt;
            this.correctAnswer = correctAnswer;
            this.options = options;
        }

        @Override
        public String getPrompt() {
            return prompt;
        }

        @Override
        public String getCorrectAnswer() {
            return correctAnswer;
        }

        @Override
        public String[] getOptions() {
            return options;
        }

        @Override
        public String getUserResponse() {
            return userResponse;
        }

        @Override
        public void setUserResponse(String response) {
            userResponse = response;
        }

        @Override
        public boolean isCorrect() {
            return getCorrectAnswer().equals(getUserResponse());
        }
    }

    public class QuestionPane extends JPanel {

        private Question question;

        public QuestionPane(Question question) {
            this.question = question;

            setLayout(new BorderLayout());

            JLabel prompt = new JLabel("<html><b>" + question.getPrompt() + "</b></html>");
            prompt.setHorizontalAlignment(JLabel.LEFT);

            add(prompt, BorderLayout.NORTH);

            JPanel guesses = new JPanel(new GridBagLayout());
            guesses.setBorder(new EmptyBorder(5, 5, 5, 5));
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.weightx = 1;
            gbc.anchor = GridBagConstraints.WEST;

            List<String> options = new ArrayList<>(Arrays.asList(question.getOptions()));
            options.add(question.getCorrectAnswer());
            Collections.sort(options);

            ButtonGroup bg = new ButtonGroup();
            for (String option : options) {
                JRadioButton btn = new JRadioButton(option);
                bg.add(btn);

                guesses.add(btn, gbc);
            }

            add(guesses);

        }

        public Question getQuestion() {
            return question;
        }

        public class ActionHandler implements ActionListener {

            @Override
            public void actionPerformed(ActionEvent e) {
                getQuestion().setUserResponse(e.getActionCommand());
            }

        }

    }

}

【讨论】:

  • 但是为什么它没有出现,我可以添加/删除什么代码来解决这个问题?
  • 为什么没有出现?因为您已经阻止了事件调度线程,该线程负责处理绘制请求等。应该添加/删除什么代码?认真地删除所有内容,您必须完全重新考虑该过程。您不能使用for/while 循环来控制问题的流程,而是需要使用 Swing Timer 作为伪循环来控制流程。这将要求您重新考虑如何提出问题以及如何监控用户输入
  • 我首先要弄清楚如何创建一个自定义组件,该组件能够提示用户提出问题并将他们的答案记录为一个工作单元,这样,您可以预先- 提前创建问题(在您开始向用户展示之前)并简单地使用List 或数组作为控制机制。这将允许您使用CardLayout 在它们之间简单地切换
  • @user2451511 这是一个艰难而复杂的主题,在几段中不容易回答,我整理了一个“示例”,说明我如何解决这个问题,供您查看,我希望我已经介绍了一些“陷阱”和更复杂的想法
  • @hamena314 如果我记得你可以使用method()(无参数)调用该方法,params 将为空,而不必执行method(null)
【解决方案2】:

如果您在此应用程序中使用了 Jframe,只需检查是否将面板添加到框架,您刚刚将标签添加到面板,只需检查是否已将面板添加到 Jframe,否则不会显示

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-24
    • 1970-01-01
    • 2013-07-21
    • 2021-07-30
    • 2013-03-15
    相关资源
    最近更新 更多