为什么我的JLabel没有出现 [英] Why is my JLabel not showing up

查看:114
本文介绍了为什么我的JLabel没有出现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am calling this method called check in one of my abstract classes but for some reason the JLabel (problem) I am adding to the JPanel (panel) is not showing up. Why is this occurring? Any explanations, I am using both the repaint, and validate methods but still nothing shows up.

推荐答案

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

The problem you're having is you're blocking the Event Dispatching Thread, prevent the UI from been updated or any new events from been processed...

它从这里开始......

It starts here...

        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是事件驱动的,某些时间点会发生某些事情并且你会对它做出回应。

You're clearly thinking in a procedural manner (like you would for a console program), but this isn't how GUIs work, GUIs are event driven, something happens at some point in time and you respond to it.

我的建议是调查Swing 计时器,这将允许您在某些时间安排回调,以及在触发时执行某些操作,可以用来修改UI,因为它在EDT的上下文中执行。

My suggestion is to investigate Swing Timer, which will allow you to schedule a call back at some, point in the future and perform some action when it is triggered, which can be used to modify the UI, as its executed within the context of the EDT.

参见 Swing中的并发如何使用Swing Timers 获取更多详细信息

See Concurrency in Swing and How to use Swing Timers for more details

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

I'd also recommend that you take a look at CardLayout, as it might make easier to change the between different views

请参阅如何使用CardLayout 获取更多详细信息

See How to Use CardLayout for more details

我非常注重代码的原则接口不实现和模型 - 视图 - 控制器。这些基本上鼓励你分离和分离责任,所以一部分的改变不会对另一部分产生负面影响。

I work very much to the principle of "Code to interface not implementation" and the Model-View-Controller. These basically encourage your to separate and isolate responsibility, so a change in one part won't adversely affect another.

这也意味着你可以插入'播放实现,解耦代码并使其更灵活。

It also means you can plug'n'play implementations, decoupling the code and making it more flexible.

从基本开始,你需要一些有文字(问题),正确答案和一些选项(或错误的答案)

Start with the basic, you need something that has some text (the question), a correct answer and some "options" (or incorrect answers)

public interface Question {

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

}

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

So, pretty basic. The question has a prompt, a right answer, some wrong answers and can manage the user response. For ease of use, it also has a isCorrect method

现在,我们需要一个实际的实现。这是一个非常基本的例子,但你可能有许多不同的实现,甚至可能包含答案类型的泛型(为了参数起见,我假设为 String

Now, we need an actual implementation. This is a pretty basic example, but you might have a number of different implementations and might even include generics for the type of answers (which I've assumed as String for argument sake)

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());
    }
}

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

Okay, that's all fine and all, but what does this actually do for us? Well, know you can create a simple component whose sole job is to present the question to the user and handle their response...

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());
        }

    }

}

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

This makes for a nice re-usable component, one which can handle a bunch of questions and not care.

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

Now, we need some way to manage multiple questions, a quiz!

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();
        }
    }
}

好的,这是一点点更复杂,但基本的是,它管理当前呈现给用户的哪个问题,管理时间并允许用户导航到下一个问题,如果他们想要的话。

Okay, this is a little more complicated, but the basics are, it manages which question is currently presented to the user, manages the time and allows the user to navigate to the next question if they want to.

现在,它很容易迷失在细节中......

Now, it's easy to get lost in the detail...

这部分代码实际设置为主视图,使用 CardLayout

This part of the code actually set's up the main "view", using a 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");

开始按钮,结束屏幕每个 QuestionPane 都会添加到 panelOfQuestions 中,该文件由 CardLayout管理,这样可以根据需要轻松翻转视图。

The start button, "end screen" and each individual QuestionPane are added to the panelOfQuestions, which is managed by a CardLayout, this makes it easy to "flip" the views as required.

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

I use a simple method to move to the next question

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();
    }
}

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

This basically increments a counter and checks to see if we've run out of questions or not. If we have, it disables the next button and shows the "last" view to the user, if not, it moves to the next question view and restarts the timeout timer.

现在,这里出现了神奇......

Now, here comes the "magic"...

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 计时器执行伪循环,这意味着它将在常规基础上调用 actionPerformed 方法,就像 for 一样循环会,但它会在不会阻止EDT的情况下完成。

The Swing Timer acts a pseudo loop, meaning that it will call the actionPerformed method on a regular bases, just like for or while loop would, but it does it in such away that it doesn't block the EDT.

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

This example adds a little more "magic" in that it acts as a count down timer, it checks how long the question has been visible to the user and presents a count down until it will automatically move to the next question, when the duration is greater then or equal to the timeOut (5 seconds in this example), it calls the nextQuestion method

但是你怎么用它?您创建列表 问题,创建 QuizPane的实例并将其添加到屏幕上显示的其他容器中,例如......

But how do you use it you ask? You create a List of Questions, create an instance of the QuizPane and add that to some other container which is displayed on the screen, for example...

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);
            }
        });
    }

}

最后,因为我认识你我想要一个完全可运行的例子

And finally, because I know you'll want one, a fully runable example

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());
            }

        }

    }

}

这篇关于为什么我的JLabel没有出现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆